summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-03-23 17:27:34 +0100
committerThomas Haller <thaller@redhat.com>2020-03-23 17:50:12 +0100
commite75d62ce763b7c571dfadc9710b9843c07110ab8 (patch)
tree74654d352c90fc4ef886ee1143e56ef22b133e7b
parent44fed3c3404efcb2a9db9e4a2ad6b87c3b9a44d8 (diff)
parent46a181603483fc7e5b64beef13744920560b3ef8 (diff)
systemd: merge branch systemd into master
-rw-r--r--Makefile.am2
-rw-r--r--shared/systemd/sd-adapt-shared/arphrd-list.h3
-rw-r--r--shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h2
-rw-r--r--shared/systemd/src/basic/cgroup-util.h251
-rw-r--r--shared/systemd/src/basic/escape.c22
-rw-r--r--shared/systemd/src/basic/escape.h15
-rw-r--r--shared/systemd/src/basic/extract-word.c2
-rw-r--r--shared/systemd/src/basic/fileio.c124
-rw-r--r--shared/systemd/src/basic/fileio.h7
-rw-r--r--shared/systemd/src/basic/format-util.h39
-rw-r--r--shared/systemd/src/basic/fs-util.c95
-rw-r--r--shared/systemd/src/basic/fs-util.h1
-rw-r--r--shared/systemd/src/basic/in-addr-util.c48
-rw-r--r--shared/systemd/src/basic/in-addr-util.h2
-rw-r--r--shared/systemd/src/basic/memory-util.h5
-rw-r--r--shared/systemd/src/basic/parse-util.c40
-rw-r--r--shared/systemd/src/basic/parse-util.h13
-rw-r--r--shared/systemd/src/basic/path-util.c26
-rw-r--r--shared/systemd/src/basic/path-util.h15
-rw-r--r--shared/systemd/src/basic/process-util.c57
-rw-r--r--shared/systemd/src/basic/process-util.h9
-rw-r--r--shared/systemd/src/basic/random-util.c14
-rw-r--r--shared/systemd/src/basic/socket-util.c271
-rw-r--r--shared/systemd/src/basic/socket-util.h19
-rw-r--r--shared/systemd/src/basic/string-table.h2
-rw-r--r--shared/systemd/src/basic/string-util.c120
-rw-r--r--shared/systemd/src/basic/string-util.h3
-rw-r--r--shared/systemd/src/basic/strv.c95
-rw-r--r--shared/systemd/src/basic/strv.h38
-rw-r--r--shared/systemd/src/basic/time-util.c27
-rw-r--r--shared/systemd/src/basic/user-util.h143
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.c55
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.h4
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-client.c86
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-client.c17
-rw-r--r--src/systemd/src/libsystemd/sd-event/sd-event.c81
-rw-r--r--src/systemd/src/libsystemd/sd-id128/id128-util.c13
-rw-r--r--src/systemd/src/libsystemd/sd-id128/id128-util.h2
-rw-r--r--src/systemd/src/libsystemd/sd-id128/sd-id128.c17
-rw-r--r--src/systemd/src/systemd/_sd-common.h12
-rw-r--r--src/systemd/src/systemd/sd-dhcp-client.h4
41 files changed, 1216 insertions, 585 deletions
diff --git a/Makefile.am b/Makefile.am
index 3ca9eac098..4cbf9aa8e8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1819,6 +1819,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
shared/systemd/nm-sd-utils-shared.c \
shared/systemd/nm-sd-utils-shared.h \
shared/systemd/sd-adapt-shared/architecture.h \
+ shared/systemd/sd-adapt-shared/arphrd-list.h \
shared/systemd/sd-adapt-shared/build.h \
shared/systemd/sd-adapt-shared/copy.h \
shared/systemd/sd-adapt-shared/def.h \
@@ -1850,6 +1851,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
shared/systemd/src/basic/alloc-util.c \
shared/systemd/src/basic/alloc-util.h \
shared/systemd/src/basic/async.h \
+ shared/systemd/src/basic/cgroup-util.h \
shared/systemd/src/basic/env-file.c \
shared/systemd/src/basic/env-file.h \
shared/systemd/src/basic/env-util.c \
diff --git a/shared/systemd/sd-adapt-shared/arphrd-list.h b/shared/systemd/sd-adapt-shared/arphrd-list.h
new file mode 100644
index 0000000000..637892c2d6
--- /dev/null
+++ b/shared/systemd/sd-adapt-shared/arphrd-list.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
index 231e06bdad..26a043f567 100644
--- a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
+++ b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
@@ -84,6 +84,8 @@ G_STMT_START { \
#include <sys/syscall.h>
#include <sys/ioctl.h>
+#define ENABLE_GSHADOW FALSE
+
/*****************************************************************************/
/* systemd cannot be compiled with "-Wdeclaration-after-statement". In particular
diff --git a/shared/systemd/src/basic/cgroup-util.h b/shared/systemd/src/basic/cgroup-util.h
new file mode 100644
index 0000000000..300555f1ac
--- /dev/null
+++ b/shared/systemd/src/basic/cgroup-util.h
@@ -0,0 +1,251 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <dirent.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+
+#include "def.h"
+#include "set.h"
+
+#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd"
+#define SYSTEMD_CGROUP_CONTROLLER_HYBRID "name=unified"
+#define SYSTEMD_CGROUP_CONTROLLER "_systemd"
+
+/* An enum of well known cgroup controllers */
+typedef enum CGroupController {
+ /* Original cgroup controllers */
+ CGROUP_CONTROLLER_CPU,
+ CGROUP_CONTROLLER_CPUACCT, /* v1 only */
+ CGROUP_CONTROLLER_CPUSET, /* v2 only */
+ CGROUP_CONTROLLER_IO, /* v2 only */
+ CGROUP_CONTROLLER_BLKIO, /* v1 only */
+ CGROUP_CONTROLLER_MEMORY,
+ CGROUP_CONTROLLER_DEVICES, /* v1 only */
+ CGROUP_CONTROLLER_PIDS,
+
+ /* BPF-based pseudo-controllers, v2 only */
+ CGROUP_CONTROLLER_BPF_FIREWALL,
+ CGROUP_CONTROLLER_BPF_DEVICES,
+
+ _CGROUP_CONTROLLER_MAX,
+ _CGROUP_CONTROLLER_INVALID = -1,
+} CGroupController;
+
+#define CGROUP_CONTROLLER_TO_MASK(c) (1U << (c))
+
+/* A bit mask of well known cgroup controllers */
+typedef enum CGroupMask {
+ CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
+ CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
+ CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET),
+ CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO),
+ CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
+ CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
+ CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES),
+ CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS),
+ CGROUP_MASK_BPF_FIREWALL = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FIREWALL),
+ CGROUP_MASK_BPF_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_DEVICES),
+
+ /* All real cgroup v1 controllers */
+ CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS,
+
+ /* All real cgroup v2 controllers */
+ CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
+
+ /* All cgroup v2 BPF pseudo-controllers */
+ CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES,
+
+ _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
+} CGroupMask;
+
+static inline CGroupMask CGROUP_MASK_EXTEND_JOINED(CGroupMask mask) {
+ /* We always mount "cpu" and "cpuacct" in the same hierarchy. Hence, when one bit is set also set the other */
+
+ if (mask & (CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT))
+ mask |= (CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT);
+
+ return mask;
+}
+
+CGroupMask get_cpu_accounting_mask(void);
+bool cpu_accounting_is_cheap(void);
+
+/* Special values for all weight knobs on unified hierarchy */
+#define CGROUP_WEIGHT_INVALID ((uint64_t) -1)
+#define CGROUP_WEIGHT_MIN UINT64_C(1)
+#define CGROUP_WEIGHT_MAX UINT64_C(10000)
+#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
+
+#define CGROUP_LIMIT_MIN UINT64_C(0)
+#define CGROUP_LIMIT_MAX ((uint64_t) -1)
+
+static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) {
+ return
+ x == CGROUP_WEIGHT_INVALID ||
+ (x >= CGROUP_WEIGHT_MIN && x <= CGROUP_WEIGHT_MAX);
+}
+
+/* IO limits on unified hierarchy */
+typedef enum CGroupIOLimitType {
+ CGROUP_IO_RBPS_MAX,
+ CGROUP_IO_WBPS_MAX,
+ CGROUP_IO_RIOPS_MAX,
+ CGROUP_IO_WIOPS_MAX,
+
+ _CGROUP_IO_LIMIT_TYPE_MAX,
+ _CGROUP_IO_LIMIT_TYPE_INVALID = -1
+} CGroupIOLimitType;
+
+extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX];
+
+const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_;
+CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_;
+
+/* Special values for the cpu.shares attribute */
+#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1)
+#define CGROUP_CPU_SHARES_MIN UINT64_C(2)
+#define CGROUP_CPU_SHARES_MAX UINT64_C(262144)
+#define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024)
+
+static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) {
+ return
+ x == CGROUP_CPU_SHARES_INVALID ||
+ (x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX);
+}
+
+/* Special values for the blkio.weight attribute */
+#define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1)
+#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10)
+#define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000)
+#define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500)
+
+static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) {
+ return
+ x == CGROUP_BLKIO_WEIGHT_INVALID ||
+ (x >= CGROUP_BLKIO_WEIGHT_MIN && x <= CGROUP_BLKIO_WEIGHT_MAX);
+}
+
+typedef enum CGroupUnified {
+ CGROUP_UNIFIED_UNKNOWN = -1,
+ CGROUP_UNIFIED_NONE = 0, /* Both systemd and controllers on legacy */
+ CGROUP_UNIFIED_SYSTEMD = 1, /* Only systemd on unified */
+ CGROUP_UNIFIED_ALL = 2, /* Both systemd and controllers on unified */
+} CGroupUnified;
+
+/*
+ * General rules:
+ *
+ * We accept named hierarchies in the syntax "foo" and "name=foo".
+ *
+ * We expect that named hierarchies do not conflict in name with a
+ * kernel hierarchy, modulo the "name=" prefix.
+ *
+ * We always generate "normalized" controller names, i.e. without the
+ * "name=" prefix.
+ *
+ * We require absolute cgroup paths. When returning, we will always
+ * generate paths with multiple adjacent / removed.
+ */
+
+int cg_enumerate_processes(const char *controller, const char *path, FILE **_f);
+int cg_read_pid(FILE *f, pid_t *_pid);
+int cg_read_event(const char *controller, const char *path, const char *event,
+ char **val);
+
+int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d);
+int cg_read_subgroup(DIR *d, char **fn);
+
+typedef enum CGroupFlags {
+ CGROUP_SIGCONT = 1 << 0,
+ CGROUP_IGNORE_SELF = 1 << 1,
+ CGROUP_REMOVE = 1 << 2,
+} CGroupFlags;
+
+typedef int (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata);
+
+int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
+int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
+
+int cg_split_spec(const char *spec, char **ret_controller, char **ret_path);
+int cg_mangle_path(const char *path, char **result);
+
+int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs);
+int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs);
+
+int cg_pid_get_path(const char *controller, pid_t pid, char **path);
+
+int cg_rmdir(const char *controller, const char *path);
+
+int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
+int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret);
+int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, char **keys, char **values);
+
+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);
+int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size);
+int cg_remove_xattr(const char *controller, const char *path, const char *name);
+
+int cg_install_release_agent(const char *controller, const char *agent);
+int cg_uninstall_release_agent(const char *controller);
+
+int cg_is_empty(const char *controller, const char *path);
+int cg_is_empty_recursive(const char *controller, const char *path);
+
+int cg_get_root_path(char **path);
+
+int cg_path_get_session(const char *path, char **session);
+int cg_path_get_owner_uid(const char *path, uid_t *uid);
+int cg_path_get_unit(const char *path, char **unit);
+int cg_path_get_user_unit(const char *path, char **unit);
+int cg_path_get_machine_name(const char *path, char **machine);
+int cg_path_get_slice(const char *path, char **slice);
+int cg_path_get_user_slice(const char *path, char **slice);
+
+int cg_shift_path(const char *cgroup, const char *cached_root, const char **shifted);
+int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **cgroup);
+
+int cg_pid_get_session(pid_t pid, char **session);
+int cg_pid_get_owner_uid(pid_t pid, uid_t *uid);
+int cg_pid_get_unit(pid_t pid, char **unit);
+int cg_pid_get_user_unit(pid_t pid, char **unit);
+int cg_pid_get_machine_name(pid_t pid, char **machine);
+int cg_pid_get_slice(pid_t pid, char **slice);
+int cg_pid_get_user_slice(pid_t pid, char **slice);
+
+int cg_path_decode_unit(const char *cgroup, char **unit);
+
+char *cg_escape(const char *p);
+char *cg_unescape(const char *p) _pure_;
+
+bool cg_controller_is_valid(const char *p);
+
+int cg_slice_to_path(const char *unit, char **ret);
+
+typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
+
+int cg_mask_supported(CGroupMask *ret);
+int cg_mask_from_string(const char *s, CGroupMask *ret);
+int cg_mask_to_string(CGroupMask mask, char **ret);
+
+int cg_kernel_controllers(Set **controllers);
+
+bool cg_ns_supported(void);
+
+int cg_all_unified(void);
+int cg_hybrid_unified(void);
+int cg_unified_controller(const char *controller);
+int cg_unified_cached(bool flush);
+static inline int cg_unified(void) {
+ return cg_unified_cached(true);
+}
+
+const char* cgroup_controller_to_string(CGroupController c) _const_;
+CGroupController cgroup_controller_from_string(const char *s) _pure_;
+
+bool is_cgroup_fs(const struct statfs *s);
+bool fd_is_cgroup_fs(int fd);
diff --git a/shared/systemd/src/basic/escape.c b/shared/systemd/src/basic/escape.c
index 06d823c762..2cc5be186a 100644
--- a/shared/systemd/src/basic/escape.c
+++ b/shared/systemd/src/basic/escape.c
@@ -104,7 +104,7 @@ char *cescape(const char *s) {
return cescape_length(s, strlen(s));
}
-int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) {
+int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul) {
int r = 1;
assert(p);
@@ -173,7 +173,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
return -EINVAL;
/* Don't allow NUL bytes */
- if (a == 0 && b == 0)
+ if (a == 0 && b == 0 && !accept_nul)
return -EINVAL;
*ret = (a << 4U) | b;
@@ -201,7 +201,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
/* Don't allow 0 chars */
- if (c == 0)
+ if (c == 0 && !accept_nul)
return -EINVAL;
*ret = c;
@@ -229,7 +229,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
/* Don't allow 0 chars */
- if (c == 0)
+ if (c == 0 && !accept_nul)
return -EINVAL;
/* Don't allow invalid code points */
@@ -269,7 +269,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
return -EINVAL;
/* don't allow NUL bytes */
- if (a == 0 && b == 0 && c == 0)
+ if (a == 0 && b == 0 && c == 0 && !accept_nul)
return -EINVAL;
/* Don't allow bytes above 255 */
@@ -290,6 +290,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
return r;
}
+#if 0 /* NM_IGNORED */
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
char *r, *t;
const char *f;
@@ -335,7 +336,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
return -EINVAL;
}
- k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit);
+ k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit, flags & UNESCAPE_ACCEPT_NUL);
if (k < 0) {
if (flags & UNESCAPE_RELAX) {
/* Invalid escape code, let's take it literal then */
@@ -362,15 +363,6 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
return t - r;
}
-int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
- return cunescape_length_with_prefix(s, length, NULL, flags, ret);
-}
-
-int cunescape(const char *s, UnescapeFlags flags, char **ret) {
- return cunescape_length(s, strlen(s), flags, ret);
-}
-
-#if 0 /* NM_IGNORED */
char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) {
char *ans, *t, *prev, *prev2;
const char *f;
diff --git a/shared/systemd/src/basic/escape.h b/shared/systemd/src/basic/escape.h
index b26054c5df..b8eb137c3d 100644
--- a/shared/systemd/src/basic/escape.h
+++ b/shared/systemd/src/basic/escape.h
@@ -29,22 +29,27 @@
#define SHELL_NEED_ESCAPE_POSIX "\\\'"
typedef enum UnescapeFlags {
- UNESCAPE_RELAX = 1,
+ UNESCAPE_RELAX = 1 << 0,
+ UNESCAPE_ACCEPT_NUL = 1 << 1,
} UnescapeFlags;
typedef enum EscapeStyle {
ESCAPE_BACKSLASH = 1,
- ESCAPE_POSIX = 2,
+ ESCAPE_POSIX = 2,
} EscapeStyle;
char *cescape(const char *s);
char *cescape_length(const char *s, size_t n);
int cescape_char(char c, char *buf);
-int cunescape(const char *s, UnescapeFlags flags, char **ret);
-int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
-int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit);
+static inline int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
+ return cunescape_length_with_prefix(s, length, NULL, flags, ret);
+}
+static inline int cunescape(const char *s, UnescapeFlags flags, char **ret) {
+ return cunescape_length(s, strlen(s), flags, ret);
+}
+int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul);
char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits);
static inline char *xescape(const char *s, const char *bad) {
diff --git a/shared/systemd/src/basic/extract-word.c b/shared/systemd/src/basic/extract-word.c
index 2da25b03d4..62f015f39a 100644
--- a/shared/systemd/src/basic/extract-word.c
+++ b/shared/systemd/src/basic/extract-word.c
@@ -92,7 +92,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
bool eight_bit = false;
char32_t u;
- r = cunescape_one(*p, (size_t) -1, &u, &eight_bit);
+ r = cunescape_one(*p, (size_t) -1, &u, &eight_bit, false);
if (r < 0) {
if (flags & EXTRACT_CUNESCAPE_RELAX) {
s[sz++] = '\\';
diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c
index 3bffa1c5f9..02d62c8999 100644
--- a/shared/systemd/src/basic/fileio.c
+++ b/shared/systemd/src/basic/fileio.c
@@ -139,16 +139,21 @@ static int write_string_file_atomic(
assert(fn);
assert(line);
+ /* Note that we'd really like to use O_TMPFILE here, but can't really, since we want replacement
+ * semantics here, and O_TMPFILE can't offer that. i.e. rename() replaces but linkat() doesn't. */
+
r = fopen_temporary(fn, &f, &p);
if (r < 0)
return r;
- (void) fchmod_umask(fileno(f), 0644);
-
r = write_string_stream_ts(f, line, flags, ts);
if (r < 0)
goto fail;
+ r = fchmod_umask(fileno(f), FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0644);
+ if (r < 0)
+ goto fail;
+
if (rename(p, fn) < 0) {
r = -errno;
goto fail;
@@ -168,7 +173,7 @@ int write_string_file_ts(
struct timespec *ts) {
_cleanup_fclose_ FILE *f = NULL;
- int q, r;
+ int q, r, fd;
assert(fn);
assert(line);
@@ -193,26 +198,20 @@ int write_string_file_ts(
} else
assert(!ts);
- if (flags & WRITE_STRING_FILE_CREATE) {
- r = fopen_unlocked(fn, "we", &f);
- if (r < 0)
- goto fail;
- } else {
- int fd;
-
- /* We manually build our own version of fopen(..., "we") that
- * works without O_CREAT */
- fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | ((flags & WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0));
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
+ /* 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_MODE_0600) ? 0600 : 0666));
+ if (fd < 0) {
+ r = -errno;
+ goto fail;
+ }
- r = fdopen_unlocked(fd, "w", &f);
- if (r < 0) {
- safe_close(fd);
- goto fail;
- }
+ r = fdopen_unlocked(fd, "w", &f);
+ if (r < 0) {
+ safe_close(fd);
+ goto fail;
}
if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
@@ -547,17 +546,19 @@ finalize:
return r;
}
-int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
+int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(filename);
assert(contents);
- r = fopen_unlocked(filename, "re", &f);
+ r = xfopenat(dir_fd, filename, "re", 0, &f);
if (r < 0)
return r;
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
return read_full_stream_full(f, filename, flags, contents, size);
}
@@ -686,6 +687,81 @@ DIR *xopendirat(int fd, const char *name, int flags) {
return d;
}
+static int mode_to_flags(const char *mode) {
+ const char *p;
+ int flags;
+
+ if ((p = startswith(mode, "r+")))
+ flags = O_RDWR;
+ else if ((p = startswith(mode, "r")))
+ flags = O_RDONLY;
+ else if ((p = startswith(mode, "w+")))
+ flags = O_RDWR|O_CREAT|O_TRUNC;
+ else if ((p = startswith(mode, "w")))
+ flags = O_WRONLY|O_CREAT|O_TRUNC;
+ else if ((p = startswith(mode, "a+")))
+ flags = O_RDWR|O_CREAT|O_APPEND;
+ else if ((p = startswith(mode, "a")))
+ flags = O_WRONLY|O_CREAT|O_APPEND;
+ else
+ return -EINVAL;
+
+ for (; *p != 0; p++) {
+
+ switch (*p) {
+
+ case 'e':
+ flags |= O_CLOEXEC;
+ break;
+
+ case 'x':
+ flags |= O_EXCL;
+ break;
+
+ case 'm':
+ /* ignore this here, fdopen() might care later though */
+ break;
+
+ case 'c': /* not sure what to do about this one */
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return flags;
+}
+
+int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret) {
+ FILE *f;
+
+ /* A combination of fopen() with openat() */
+
+ if (dir_fd == AT_FDCWD && flags == 0) {
+ f = fopen(path, mode);
+ if (!f)
+ return -errno;
+ } else {
+ int fd, mode_flags;
+
+ mode_flags = mode_to_flags(mode);
+ if (mode_flags < 0)
+ return mode_flags;
+
+ fd = openat(dir_fd, path, mode_flags | flags);
+ if (fd < 0)
+ return -errno;
+
+ f = fdopen(fd, mode);
+ if (!f) {
+ safe_close(fd);
+ return -errno;
+ }
+ }
+
+ *ret = f;
+ return 0;
+}
+
#if 0 /* NM_IGNORED */
static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
char **i;
diff --git a/shared/systemd/src/basic/fileio.h b/shared/systemd/src/basic/fileio.h
index 31bfef33ac..e6fea2afd4 100644
--- a/shared/systemd/src/basic/fileio.h
+++ b/shared/systemd/src/basic/fileio.h
@@ -6,6 +6,7 @@
#include <stddef.h>
#include <stdio.h>
#include <sys/stat.h>
+#include <sys/fcntl.h>
#include <sys/types.h>
#include "macro.h"
@@ -22,6 +23,7 @@ typedef enum {
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,
/* 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()
@@ -52,9 +54,9 @@ 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(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
+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(filename, 0, contents, size);
+ return read_full_file_full(AT_FDCWD, filename, 0, contents, 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);
@@ -69,6 +71,7 @@ int executable_is_script(const char *path, char **interpreter);
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
DIR *xopendirat(int dirfd, const char *name, int flags);
+int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret);
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
diff --git a/shared/systemd/src/basic/format-util.h b/shared/systemd/src/basic/format-util.h
index 59622508a3..c47fa76ea8 100644
--- a/shared/systemd/src/basic/format-util.h
+++ b/shared/systemd/src/basic/format-util.h
@@ -5,30 +5,18 @@
#include <net/if.h>
#include <stdbool.h>
-#if SIZEOF_PID_T == 4
-# define PID_PRI PRIi32
-#elif SIZEOF_PID_T == 2
-# define PID_PRI PRIi16
-#else
-# error Unknown pid_t size
-#endif
+#include "cgroup-util.h"
+#include "macro.h"
+
+assert_cc(sizeof(pid_t) == sizeof(int32_t));
+#define PID_PRI PRIi32
#define PID_FMT "%" PID_PRI
-#if SIZEOF_UID_T == 4
-# define UID_FMT "%" PRIu32
-#elif SIZEOF_UID_T == 2
-# define UID_FMT "%" PRIu16
-#else
-# error Unknown uid_t size
-#endif
+assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+#define UID_FMT "%" PRIu32
-#if SIZEOF_GID_T == 4
-# define GID_FMT "%" PRIu32
-#elif SIZEOF_GID_T == 2
-# define GID_FMT "%" PRIu16
-#else
-# error Unknown gid_t size
-#endif
+assert_cc(sizeof(gid_t) == sizeof(uint32_t));
+#define GID_FMT "%" PRIu32
#if SIZEOF_TIME_T == 8
# define PRI_TIME PRIi64
@@ -84,8 +72,15 @@ typedef enum {
FORMAT_BYTES_TRAILING_B = 1 << 2,
} FormatBytesFlag;
-#define FORMAT_BYTES_MAX 8
+#define FORMAT_BYTES_MAX 16
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");
+ return buf;
+ }
+ return format_bytes(buf, l, t);
+}
diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c
index 5964639026..7996657108 100644
--- a/shared/systemd/src/basic/fs-util.c
+++ b/shared/systemd/src/basic/fs-util.c
@@ -276,7 +276,52 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
return do_chown || do_chmod;
}
-#endif /* NM_IGNORED */
+
+int chmod_and_chown_unsafe(const char *path, mode_t mode, uid_t uid, gid_t gid) {
+ bool do_chown, do_chmod;
+ struct stat st;
+
+ assert(path);
+
+ /* Change ownership and access mode of the specified path, see description of fchmod_and_chown().
+ * Should only be used on trusted paths. */
+
+ if (lstat(path, &st) < 0)
+ return -errno;
+
+ do_chown =
+ (uid != UID_INVALID && st.st_uid != uid) ||
+ (gid != GID_INVALID && st.st_gid != gid);
+
+ do_chmod =
+ !S_ISLNK(st.st_mode) && /* chmod is not defined on symlinks */
+ ((mode != MODE_INVALID && ((st.st_mode ^ mode) & 07777) != 0) ||
+ do_chown); /* If we change ownership, make sure we reset the mode afterwards, since chown()
+ * modifies the access mode too */
+
+ if (mode == MODE_INVALID)
+ mode = st.st_mode; /* If we only shall do a chown(), save original mode, since chown() might break it. */
+ else if ((mode & S_IFMT) != 0 && ((mode ^ st.st_mode) & S_IFMT) != 0)
+ return -EINVAL; /* insist on the right file type if it was specified */
+
+ if (do_chown && do_chmod) {
+ mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */
+
+ if (((minimal ^ st.st_mode) & 07777) != 0)
+ if (chmod(path, minimal & 07777) < 0)
+ return -errno;
+ }
+
+ if (do_chown)
+ if (lchown(path, uid, gid) < 0)
+ return -errno;
+
+ if (do_chmod)
+ if (chmod(path, mode & 07777) < 0)
+ return -errno;
+
+ return do_chown || do_chmod;
+}
int fchmod_umask(int fd, mode_t m) {
mode_t u;
@@ -289,7 +334,6 @@ int fchmod_umask(int fd, mode_t m) {
return r;
}
-#if 0 /* NM_IGNORED */
int fchmod_opath(int fd, mode_t m) {
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
@@ -810,6 +854,14 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (r < 0)
return r;
+ /* Simplify the root directory, so that it has no duplicate slashes and nothing at the
+ * end. While we won't resolve the root path we still simplify it. Note that dropping the
+ * trailing slash should not change behaviour, since when opening it we specify O_DIRECTORY
+ * anyway. Moreover at the end of this function after processing everything we'll always turn
+ * the empty string back to "/". */
+ delete_trailing_chars(root, "/");
+ path_simplify(root, true);
+
if (flags & CHASE_PREFIX_ROOT) {
/* We don't support relative paths in combination with a root directory */
if (!path_is_absolute(path))
@@ -823,7 +875,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (r < 0)
return r;
- fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
+ fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
if (fd < 0)
return -errno;
@@ -832,6 +884,31 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
return -errno;
}
+ if (root) {
+ _cleanup_free_ char *absolute = NULL;
+ const char *e;
+
+ /* If we are operating on a root directory, let's take the root directory as it is. */
+
+ e = path_startswith(buffer, root);
+ if (!e)
+ return log_full_errno(flags & CHASE_WARN ? LOG_WARNING : LOG_DEBUG,
+ SYNTHETIC_ERRNO(ECHRNG),
+ "Specified path '%s' is outside of specified root directory '%s', refusing to resolve.",
+ path, root);
+
+ done = strdup(root);
+ if (!done)
+ return -ENOMEM;
+
+ /* Make sure "todo" starts with a slash */
+ absolute = strjoin("/", e);
+ if (!absolute)
+ return -ENOMEM;
+
+ free_and_replace(buffer, absolute);
+ }
+
todo = buffer;
for (;;) {
_cleanup_free_ char *first = NULL;
@@ -841,6 +918,15 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
/* Determine length of first component in the path */
n = strspn(todo, "/"); /* The slashes */
+
+ if (n > 1) {
+ /* If we are looking at more than a single slash then skip all but one, so that when
+ * we are done with everything we have a normalized path with only single slashes
+ * separating the path components. */
+ todo += n - 1;
+ n = 1;
+ }
+
m = n + strcspn(todo + n, "/"); /* The entire length of the component */
/* Extract the first component. */
@@ -943,7 +1029,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(child, &st) < 0)
return -errno;
if ((flags & CHASE_SAFE) &&
- (empty_or_root(root) || (size_t)(todo - buffer) > strlen(root)) &&
unsafe_transition(&previous_stat, &st))
return log_unsafe_transition(fd, child, path, flags);
@@ -974,7 +1059,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
* directory as base. */
safe_close(fd);
- fd = open(root ?: "/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
+ fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
if (fd < 0)
return -errno;
diff --git a/shared/systemd/src/basic/fs-util.h b/shared/systemd/src/basic/fs-util.h
index 78d68be9fd..6b9ade2ec1 100644
--- a/shared/systemd/src/basic/fs-util.h
+++ b/shared/systemd/src/basic/fs-util.h
@@ -34,6 +34,7 @@ int readlink_and_make_absolute(const char *p, char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid);
+int chmod_and_chown_unsafe(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_umask(int fd, mode_t mode);
int fchmod_opath(int fd, mode_t m);
diff --git a/shared/systemd/src/basic/in-addr-util.c b/shared/systemd/src/basic/in-addr-util.c
index 91d687c208..0e77062101 100644
--- a/shared/systemd/src/basic/in-addr-util.c
+++ b/shared/systemd/src/basic/in-addr-util.c
@@ -445,54 +445,6 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union
return -EINVAL;
}
-#if 0 /* NM_IGNORED */
-int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
- _cleanup_free_ char *buf = NULL;
- const char *suffix;
- int r, ifi = 0;
-
- assert(s);
- assert(family);
- assert(ret);
-
- /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
- * if one is found. */
-
- suffix = strchr(s, '%');
- if (suffix) {
-
- if (ifindex) {
- /* If we shall return the interface index, try to parse it */
- r = parse_ifindex(suffix + 1, &ifi);
- if (r < 0) {
- unsigned u;
-
- u = if_nametoindex(suffix + 1);
- if (u <= 0)
- return -errno;
-
- ifi = (int) u;
- }
- }
-
- buf = strndup(s, suffix - s);
- if (!buf)
- return -ENOMEM;
-
- s = buf;
- }
-
- r = in_addr_from_string_auto(s, family, ret);
- if (r < 0)
- return r;
-
- if (ifindex)
- *ifindex = ifi;
-
- return r;
-}
-#endif /* NM_IGNORED */
-
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
assert(addr);
diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h
index 28afc7d86c..ae2dad0bb1 100644
--- a/shared/systemd/src/basic/in-addr-util.h
+++ b/shared/systemd/src/basic/in-addr-util.h
@@ -42,7 +42,7 @@ int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
-int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
+
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h
index 4f92a6434a..b7e2e67e84 100644
--- a/shared/systemd/src/basic/memory-util.h
+++ b/shared/systemd/src/basic/memory-util.h
@@ -7,6 +7,7 @@
#include <string.h>
#include <sys/types.h>
+#include "alloc-util.h"
#include "macro.h"
size_t page_size(void) _pure_;
@@ -88,9 +89,7 @@ static inline void* erase_and_free(void *p) {
l = malloc_usable_size(p);
explicit_bzero_safe(p, l);
- free(p);
-
- return NULL;
+ return mfree(p);
}
static inline void erase_and_freep(void *p) {
diff --git a/shared/systemd/src/basic/parse-util.c b/shared/systemd/src/basic/parse-util.c
index 1199ca8003..475a06ccf8 100644
--- a/shared/systemd/src/basic/parse-util.c
+++ b/shared/systemd/src/basic/parse-util.c
@@ -82,11 +82,10 @@ int parse_mode(const char *s, mode_t *ret) {
return 0;
}
-int parse_ifindex(const char *s, int *ret) {
+int parse_ifindex(const char *s) {
int ifi, r;
assert(s);
- assert(ret);
r = safe_atoi(s, &ifi);
if (r < 0)
@@ -94,26 +93,7 @@ int parse_ifindex(const char *s, int *ret) {
if (ifi <= 0)
return -EINVAL;
- *ret = ifi;
- return 0;
-}
-
-int parse_ifindex_or_ifname(const char *s, int *ret) {
- int r;
-
- assert(s);
- assert(ret);
-
- r = parse_ifindex(s, ret);
- if (r >= 0)
- return r;
-
- r = (int) if_nametoindex(s);
- if (r <= 0)
- return -errno;
-
- *ret = r;
- return 0;
+ return ifi;
}
int parse_mtu(int family, const char *s, uint32_t *ret) {
@@ -723,6 +703,22 @@ int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
return 0;
}
+int parse_ip_prefix_length(const char *s, int *ret) {
+ unsigned l;
+ int r;
+
+ r = safe_atou(s, &l);
+ if (r < 0)
+ return r;
+
+ if (l > 128)
+ return -ERANGE;
+
+ *ret = (int) l;
+
+ return 0;
+}
+
int parse_dev(const char *s, dev_t *ret) {
const char *major;
unsigned x, y;
diff --git a/shared/systemd/src/basic/parse-util.h b/shared/systemd/src/basic/parse-util.h
index 3a70b79276..36d76ba576 100644
--- a/shared/systemd/src/basic/parse-util.h
+++ b/shared/systemd/src/basic/parse-util.h
@@ -13,8 +13,7 @@ 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);
int parse_mode(const char *s, mode_t *ret);
-int parse_ifindex(const char *s, int *ret);
-int parse_ifindex_or_ifname(const char *s, int *ret);
+int parse_ifindex(const char *s);
int parse_mtu(int family, const char *s, uint32_t *ret);
int parse_size(const char *t, uint64_t base, uint64_t *size);
@@ -46,9 +45,13 @@ static inline int safe_atoux16(const char *s, uint16_t *ret) {
int safe_atoi16(const char *s, int16_t *ret);
-static inline int safe_atou32(const char *s, uint32_t *ret_u) {
+static inline int safe_atou32_full(const char *s, unsigned base, uint32_t *ret_u) {
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
- return safe_atou(s, (unsigned*) ret_u);
+ return safe_atou_full(s, base, (unsigned*) ret_u);
+}
+
+static inline int safe_atou32(const char *s, uint32_t *ret_u) {
+ return safe_atou32_full(s, 0, (unsigned*) ret_u);
}
static inline int safe_atoi32(const char *s, int32_t *ret_i) {
@@ -113,4 +116,6 @@ int parse_nice(const char *p, int *ret);
int parse_ip_port(const char *s, uint16_t *ret);
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);
diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c
index 4250ea1872..7baab4be50 100644
--- a/shared/systemd/src/basic/path-util.c
+++ b/shared/systemd/src/basic/path-util.c
@@ -1128,4 +1128,30 @@ bool empty_or_root(const char *root) {
return root[strspn(root, "/")] == 0;
}
+
+bool path_strv_contains(char **l, const char *path) {
+ char **i;
+
+ STRV_FOREACH(i, l)
+ if (path_equal(*i, path))
+ return true;
+
+ return false;
+}
+
+bool prefixed_path_strv_contains(char **l, const char *path) {
+ char **i, *j;
+
+ STRV_FOREACH(i, l) {
+ j = *i;
+ if (*j == '-')
+ j++;
+ if (*j == '+')
+ j++;
+ if (path_equal(j, path))
+ return true;
+ }
+
+ return false;
+}
#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/path-util.h b/shared/systemd/src/basic/path-util.h
index 88aef2f377..aba8ad00fe 100644
--- a/shared/systemd/src/basic/path-util.h
+++ b/shared/systemd/src/basic/path-util.h
@@ -73,17 +73,7 @@ static inline bool path_equal_ptr(const char *a, const char *b) {
}
/* Note: the search terminates on the first NULL item. */
-#define PATH_IN_SET(p, ...) \
- ({ \
- char **_s; \
- bool _found = false; \
- STRV_FOREACH(_s, STRV_MAKE(__VA_ARGS__)) \
- if (path_equal(p, *_s)) { \
- _found = true; \
- break; \
- } \
- _found; \
- })
+#define PATH_IN_SET(p, ...) path_strv_contains(STRV_MAKE(__VA_ARGS__), p)
char* path_startswith_strv(const char *p, char **set);
#define PATH_STARTSWITH_SET(p, ...) path_startswith_strv(p, STRV_MAKE(__VA_ARGS__))
@@ -183,3 +173,6 @@ bool empty_or_root(const char *root);
static inline const char *empty_to_root(const char *path) {
return isempty(path) ? "/" : path;
}
+
+bool path_strv_contains(char **l, const char *path);
+bool prefixed_path_strv_contains(char **l, const char *path);
diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c
index deba989a46..57c84fd868 100644
--- a/shared/systemd/src/basic/process-util.c
+++ b/shared/systemd/src/basic/process-util.c
@@ -26,6 +26,7 @@
#include "alloc-util.h"
#include "architecture.h"
#include "env-util.h"
+#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
@@ -1537,6 +1538,62 @@ int pidfd_get_pid(int fd, pid_t *ret) {
return parse_pid(p, ret);
}
+static int rlimit_to_nice(rlim_t limit) {
+ if (limit <= 1)
+ return PRIO_MAX-1; /* i.e. 19 */
+
+ if (limit >= -PRIO_MIN + PRIO_MAX)
+ return PRIO_MIN; /* i.e. -20 */
+
+ return PRIO_MAX - (int) limit;
+}
+
+int setpriority_closest(int priority) {
+ int current, limit, saved_errno;
+ struct rlimit highest;
+
+ /* Try to set requested nice level */
+ if (setpriority(PRIO_PROCESS, 0, priority) >= 0)
+ return 1;
+
+ /* Permission failed */
+ saved_errno = -errno;
+ if (!ERRNO_IS_PRIVILEGE(saved_errno))
+ return saved_errno;
+
+ errno = 0;
+ current = getpriority(PRIO_PROCESS, 0);
+ if (errno != 0)
+ return -errno;
+
+ if (priority == current)
+ return 1;
+
+ /* Hmm, we'd expect that raising the nice level from our status quo would always work. If it doesn't,
+ * then the whole setpriority() system call is blocked to us, hence let's propagate the error
+ * right-away */
+ if (priority > current)
+ return saved_errno;
+
+ if (getrlimit(RLIMIT_NICE, &highest) < 0)
+ return -errno;
+
+ limit = rlimit_to_nice(highest.rlim_cur);
+
+ /* We are already less nice than limit allows us */
+ if (current < limit) {
+ log_debug("Cannot raise nice level, permissions and the resource limit do not allow it.");
+ return 0;
+ }
+
+ /* Push to the allowed limit */
+ if (setpriority(PRIO_PROCESS, 0, limit) < 0)
+ return -errno;
+
+ log_debug("Cannot set requested nice level (%i), used next best (%i).", priority, limit);
+ return 0;
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h
index cb96b43f21..7b70c9f300 100644
--- a/shared/systemd/src/basic/process-util.h
+++ b/shared/systemd/src/basic/process-util.h
@@ -174,7 +174,6 @@ int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid
int set_oom_score_adjust(int value);
-#if SIZEOF_PID_T == 4
/* The highest possibly (theoretic) pid_t value on this architecture. */
#define PID_T_MAX ((pid_t) INT32_MAX)
/* The maximum number of concurrent processes Linux allows on this architecture, as well as the highest valid PID value
@@ -184,12 +183,6 @@ int set_oom_score_adjust(int value);
* these values are documented in proc(5) we feel quite confident that they are stable enough for the near future at
* least to define them here too. */
#define TASKS_MAX 4194303U
-#elif SIZEOF_PID_T == 2
-#define PID_T_MAX ((pid_t) INT16_MAX)
-#define TASKS_MAX 32767U
-#else
-#error "Unknown pid_t size"
-#endif
assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
@@ -202,3 +195,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
})
int pidfd_get_pid(int fd, pid_t *ret);
+
+int setpriority_closest(int priority);
diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c
index 86917ca3c7..1a29494466 100644
--- a/shared/systemd/src/basic/random-util.c
+++ b/shared/systemd/src/basic/random-util.c
@@ -9,6 +9,7 @@
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
+#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
@@ -30,6 +31,8 @@
#include "siphash24.h"
#include "time-util.h"
+static bool srand_called = false;
+
int rdrand(unsigned long *ret) {
/* So, you are a "security researcher", and you wonder why we bother with using raw RDRAND here,
@@ -281,8 +284,12 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
return loop_read_exact(fd, p, n, true);
}
+static void clear_srand_initialization(void) {
+ srand_called = false;
+}
+
void initialize_srand(void) {
- static bool srand_called = false;
+ static bool pthread_atfork_registered = false;
unsigned x;
#if HAVE_SYS_AUXV_H
const void *auxv;
@@ -318,6 +325,11 @@ void initialize_srand(void) {
srand(x);
srand_called = true;
+
+ if (!pthread_atfork_registered) {
+ (void) pthread_atfork(NULL, NULL, clear_srand_initialization);
+ pthread_atfork_registered = true;
+ }
}
/* INT_MAX gives us only 31 bits, so use 24 out of that. */
diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c
index cded4545c1..452b9ced20 100644
--- a/shared/systemd/src/basic/socket-util.c
+++ b/shared/systemd/src/basic/socket-util.c
@@ -15,6 +15,9 @@
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
+#if 0 /* NM_IGNORED */
+#include <linux/if.h>
+#endif /* NM_IGNORED */
#include "alloc-util.h"
#include "errno-util.h"
@@ -44,237 +47,16 @@
#endif
static const char* const socket_address_type_table[] = {
- [SOCK_STREAM] = "Stream",
- [SOCK_DGRAM] = "Datagram",
- [SOCK_RAW] = "Raw",
- [SOCK_RDM] = "ReliableDatagram",
+ [SOCK_STREAM] = "Stream",
+ [SOCK_DGRAM] = "Datagram",
+ [SOCK_RAW] = "Raw",
+ [SOCK_RDM] = "ReliableDatagram",
[SOCK_SEQPACKET] = "SequentialPacket",
- [SOCK_DCCP] = "DatagramCongestionControl",
+ [SOCK_DCCP] = "DatagramCongestionControl",
};
DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int);
-int socket_address_parse(SocketAddress *a, const char *s) {
- _cleanup_free_ char *n = NULL;
- char *e;
- int r;
-
- assert(a);
- assert(s);
-
- *a = (SocketAddress) {
- .type = SOCK_STREAM,
- };
-
- if (*s == '[') {
- uint16_t port;
-
- /* IPv6 in [x:.....:z]:p notation */
-
- e = strchr(s+1, ']');
- if (!e)
- return -EINVAL;
-
- n = strndup(s+1, e-s-1);
- if (!n)
- return -ENOMEM;
-
- errno = 0;
- if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
- return errno_or_else(EINVAL);
-
- e++;
- if (*e != ':')
- return -EINVAL;
-
- e++;
- r = parse_ip_port(e, &port);
- if (r < 0)
- return r;
-
- a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htobe16(port);
- a->size = sizeof(struct sockaddr_in6);
-
- } else if (*s == '/') {
- /* AF_UNIX socket */
-
- size_t l;
-
- l = strlen(s);
- if (l >= sizeof(a->sockaddr.un.sun_path)) /* Note that we refuse non-NUL-terminated sockets when
- * parsing (the kernel itself is less strict here in what it
- * accepts) */
- return -EINVAL;
-
- a->sockaddr.un.sun_family = AF_UNIX;
- memcpy(a->sockaddr.un.sun_path, s, l);
- a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
-
- } else if (*s == '@') {
- /* Abstract AF_UNIX socket */
- size_t l;
-
- l = strlen(s+1);
- if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminated sockets here
- * when parsing, even though abstract namespace sockets
- * explicitly allow embedded NUL bytes and don't consider
- * them special. But it's simply annoying to debug such
- * sockets. */
- return -EINVAL;
-
- a->sockaddr.un.sun_family = AF_UNIX;
- memcpy(a->sockaddr.un.sun_path+1, s+1, l);
- a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
-
- } else if (startswith(s, "vsock:")) {
- /* AF_VSOCK socket in vsock:cid:port notation */
- const char *cid_start = s + STRLEN("vsock:");
- unsigned port;
-
- e = strchr(cid_start, ':');
- if (!e)
- return -EINVAL;
-
- r = safe_atou(e+1, &port);
- if (r < 0)
- return r;
-
- n = strndup(cid_start, e - cid_start);
- if (!n)
- return -ENOMEM;
-
- if (!isempty(n)) {
- r = safe_atou(n, &a->sockaddr.vm.svm_cid);
- if (r < 0)
- return r;
- } else
- a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
-
- a->sockaddr.vm.svm_family = AF_VSOCK;
- a->sockaddr.vm.svm_port = port;
- a->size = sizeof(struct sockaddr_vm);
-
- } else {
- uint16_t port;
-
- e = strchr(s, ':');
- if (e) {
- r = parse_ip_port(e + 1, &port);
- if (r < 0)
- return r;
-
- n = strndup(s, e-s);
- if (!n)
- return -ENOMEM;
-
- /* IPv4 in w.x.y.z:p notation? */
- r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
- if (r < 0)
- return -errno;
-
- if (r > 0) {
- /* Gotcha, it's a traditional IPv4 address */
- a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htobe16(port);
- a->size = sizeof(struct sockaddr_in);
- } else {
- unsigned idx;
-
- if (strlen(n) > IF_NAMESIZE-1)
- return -EINVAL;
-
- /* Uh, our last resort, an interface name */
- idx = if_nametoindex(n);
- if (idx == 0)
- return -EINVAL;
-
- a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htobe16(port);
- a->sockaddr.in6.sin6_scope_id = idx;
- a->sockaddr.in6.sin6_addr = in6addr_any;
- a->size = sizeof(struct sockaddr_in6);
- }
- } else {
-
- /* Just a port */
- r = parse_ip_port(s, &port);
- if (r < 0)
- return r;
-
- if (socket_ipv6_is_supported()) {
- a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htobe16(port);
- a->sockaddr.in6.sin6_addr = in6addr_any;
- a->size = sizeof(struct sockaddr_in6);
- } else {
- a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htobe16(port);
- a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
- a->size = sizeof(struct sockaddr_in);
- }
- }
- }
-
- return 0;
-}
-
-int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
- SocketAddress b;
- int r;
-
- /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
-
- r = socket_address_parse(&b, s);
- if (r < 0)
- return r;
-
- if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
- log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
- return -EAFNOSUPPORT;
- }
-
- *a = b;
- return 0;
-}
-
-int socket_address_parse_netlink(SocketAddress *a, const char *s) {
- _cleanup_free_ char *word = NULL;
- unsigned group = 0;
- int family, r;
-
- assert(a);
- assert(s);
-
- zero(*a);
- a->type = SOCK_RAW;
-
- r = extract_first_word(&s, &word, NULL, 0);
- if (r < 0)
- return r;
- if (r == 0)
- return -EINVAL;
-
- family = netlink_family_from_string(word);
- if (family < 0)
- return -EINVAL;
-
- if (!isempty(s)) {
- r = safe_atou(s, &group);
- if (r < 0)
- return r;
- }
-
- a->sockaddr.nl.nl_family = AF_NETLINK;
- a->sockaddr.nl.nl_groups = group;
-
- a->type = SOCK_RAW;
- a->size = sizeof(struct sockaddr_nl);
- a->protocol = family;
-
- return 0;
-}
-
int socket_address_verify(const SocketAddress *a, bool strict) {
assert(a);
@@ -484,32 +266,6 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
return true;
}
-bool socket_address_is(const SocketAddress *a, const char *s, int type) {
- struct SocketAddress b;
-
- assert(a);
- assert(s);
-
- if (socket_address_parse(&b, s) < 0)
- return false;
-
- b.type = type;
-
- return socket_address_equal(a, &b);
-}
-
-bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
- struct SocketAddress b;
-
- assert(a);
- assert(s);
-
- if (socket_address_parse_netlink(&b, s) < 0)
- return false;
-
- return socket_address_equal(a, &b);
-}
-
const char* socket_address_get_path(const SocketAddress *a) {
assert(a);
@@ -912,7 +668,7 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
-bool ifname_valid(const char *p) {
+bool ifname_valid_full(const char *p, bool alternative) {
bool numeric = true;
/* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
@@ -922,8 +678,13 @@ bool ifname_valid(const char *p) {
if (isempty(p))
return false;
- if (strlen(p) >= IFNAMSIZ)
- return false;
+ if (alternative) {
+ if (strlen(p) >= ALTIFNAMSIZ)
+ return false;
+ } else {
+ if (strlen(p) >= IFNAMSIZ)
+ return false;
+ }
if (dot_or_dot_dot(p))
return false;
diff --git a/shared/systemd/src/basic/socket-util.h b/shared/systemd/src/basic/socket-util.h
index a0886e0e89..2596c540ca 100644
--- a/shared/systemd/src/basic/socket-util.h
+++ b/shared/systemd/src/basic/socket-util.h
@@ -43,6 +43,8 @@ union sockaddr_union {
uint8_t un_buffer[sizeof(struct sockaddr_un) + 1];
};
+#define SUN_PATH_LEN (sizeof(((struct sockaddr_un){}).sun_path))
+
typedef struct SocketAddress {
union sockaddr_union sockaddr;
@@ -70,12 +72,6 @@ typedef enum SocketAddressBindIPv6Only {
const char* socket_address_type_to_string(int t) _const_;
int socket_address_type_from_string(const char *s) _pure_;
-int socket_address_parse(SocketAddress *a, const char *s);
-int socket_address_parse_and_warn(SocketAddress *a, const char *s);
-int socket_address_parse_netlink(SocketAddress *a, const char *s);
-int socket_address_print(const SocketAddress *a, char **p);
-int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
-
int sockaddr_un_unlink(const struct sockaddr_un *sa);
static inline int socket_address_unlink(const SocketAddress *a) {
@@ -96,11 +92,9 @@ int socket_address_listen(
mode_t directory_mode,
mode_t socket_mode,
const char *label);
-int make_socket_fd(int log_level, const char* address, int type, int flags);
-
-bool socket_address_is(const SocketAddress *a, const char *s, int type);
-bool socket_address_is_netlink(const SocketAddress *a, const char *s);
+int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
+int socket_address_print(const SocketAddress *a, char **p);
bool socket_address_matches_fd(const SocketAddress *a, int fd);
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_;
@@ -132,7 +126,10 @@ int fd_inc_rcvbuf(int fd, size_t n);
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
-bool ifname_valid(const char *p);
+bool ifname_valid_full(const char *p, bool alternative);
+static inline bool ifname_valid(const char *p) {
+ return ifname_valid_full(p, false);
+}
bool address_label_valid(const char *p);
int getpeercred(int fd, struct ucred *ucred);
diff --git a/shared/systemd/src/basic/string-table.h b/shared/systemd/src/basic/string-table.h
index 2d3cf81435..96924778f5 100644
--- a/shared/systemd/src/basic/string-table.h
+++ b/shared/systemd/src/basic/string-table.h
@@ -44,7 +44,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
char *s; \
if (i < 0 || i > max) \
return -ERANGE; \
- if (i < (type) ELEMENTSOF(name##_table)) { \
+ if (i < (type) ELEMENTSOF(name##_table) && name##_table[i]) { \
s = strdup(name##_table[i]); \
if (!s) \
return -ENOMEM; \
diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c
index 38cccdaf05..333da61ab1 100644
--- a/shared/systemd/src/basic/string-util.c
+++ b/shared/systemd/src/basic/string-util.c
@@ -1062,6 +1062,8 @@ bool string_is_safe(const char *p) {
if (!p)
return false;
+ /* Checks if the specified string contains no quotes or control characters */
+
for (t = p; *t; t++) {
if (*t > 0 && *t < ' ') /* no control characters */
return false;
@@ -1083,4 +1085,122 @@ char* string_erase(char *x) {
explicit_bzero_safe(x, strlen(x));
return x;
}
+
+int string_truncate_lines(const char *s, size_t n_lines, char **ret) {
+ const char *p = s, *e = s;
+ bool truncation_applied = false;
+ char *copy;
+ size_t n = 0;
+
+ assert(s);
+
+ /* Truncate after the specified number of lines. Returns > 0 if a truncation was applied or == 0 if
+ * there were fewer lines in the string anyway. Trailing newlines on input are ignored, and not
+ * generated either. */
+
+ for (;;) {
+ size_t k;
+
+ k = strcspn(p, "\n");
+
+ if (p[k] == 0) {
+ if (k == 0) /* final empty line */
+ break;
+
+ if (n >= n_lines) /* above threshold */
+ break;
+
+ e = p + k; /* last line to include */
+ break;
+ }
+
+ assert(p[k] == '\n');
+
+ if (n >= n_lines)
+ break;
+
+ if (k > 0)
+ e = p + k;
+
+ p += k + 1;
+ n++;
+ }
+
+ /* e points after the last character we want to keep */
+ if (isempty(e))
+ copy = strdup(s);
+ else {
+ if (!in_charset(e, "\n")) /* We only consider things truncated if we remove something that
+ * isn't a new-line or a series of them */
+ truncation_applied = true;
+
+ copy = strndup(s, e - s);
+ }
+ if (!copy)
+ return -ENOMEM;
+
+ *ret = copy;
+ return truncation_applied;
+}
+
+int string_extract_line(const char *s, size_t i, char **ret) {
+ const char *p = s;
+ size_t c = 0;
+
+ /* Extract the i'nth line from the specified string. Returns > 0 if there are more lines after that,
+ * and == 0 if we are looking at the last line or already beyond the last line. As special
+ * optimization, if the first line is requested and the string only consists of one line we return
+ * NULL, indicating the input string should be used as is, and avoid a memory allocation for a very
+ * common case. */
+
+ for (;;) {
+ const char *q;
+
+ q = strchr(p, '\n');
+ if (i == c) {
+ /* The line we are looking for! */
+
+ if (q) {
+ char *m;
+
+ m = strndup(p, q - p);
+ if (!m)
+ return -ENOMEM;
+
+ *ret = m;
+ return !isempty(q + 1); /* more coming? */
+ } else {
+ if (p == s)
+ *ret = NULL; /* Just use the input string */
+ else {
+ char *m;
+
+ m = strdup(p);
+ if (!m)
+ return -ENOMEM;
+
+ *ret = m;
+ }
+
+ return 0; /* The end */
+ }
+ }
+
+ if (!q) {
+ char *m;
+
+ /* No more lines, return empty line */
+
+ m = strdup("");
+ if (!m)
+ return -ENOMEM;
+
+ *ret = m;
+ return 0; /* The end */
+ }
+
+ p = q + 1;
+ c++;
+ }
+}
#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h
index f10af9ad2f..f98fbdddda 100644
--- a/shared/systemd/src/basic/string-util.h
+++ b/shared/systemd/src/basic/string-util.h
@@ -280,3 +280,6 @@ static inline char* str_realloc(char **p) {
}
char* string_erase(char *x);
+
+int string_truncate_lines(const char *s, size_t n_lines, char **ret);
+int string_extract_line(const char *s, size_t i, char **ret);
diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c
index b773254bab..be1c8325b6 100644
--- a/shared/systemd/src/basic/strv.c
+++ b/shared/systemd/src/basic/strv.c
@@ -18,8 +18,8 @@
#include "string-util.h"
#include "strv.h"
-char *strv_find(char **l, const char *name) {
- char **i;
+char *strv_find(char * const *l, const char *name) {
+ char * const *i;
assert(name);
@@ -30,8 +30,8 @@ char *strv_find(char **l, const char *name) {
return NULL;
}
-char *strv_find_prefix(char **l, const char *name) {
- char **i;
+char *strv_find_prefix(char * const *l, const char *name) {
+ char * const *i;
assert(name);
@@ -42,8 +42,8 @@ char *strv_find_prefix(char **l, const char *name) {
return NULL;
}
-char *strv_find_startswith(char **l, const char *name) {
- char **i, *e;
+char *strv_find_startswith(char * const *l, const char *name) {
+ char * const *i, *e;
assert(name);
@@ -59,20 +59,15 @@ char *strv_find_startswith(char **l, const char *name) {
return NULL;
}
-void strv_clear(char **l) {
+char **strv_free(char **l) {
char **k;
if (!l)
- return;
+ return NULL;
for (k = l; *k; k++)
free(*k);
- *l = NULL;
-}
-
-char **strv_free(char **l) {
- strv_clear(l);
return mfree(l);
}
@@ -183,8 +178,8 @@ char **strv_new_internal(const char *x, ...) {
return r;
}
-int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
- char **s, **t;
+int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
+ char * const *s, **t;
size_t p, q, i = 0, j;
assert(a);
@@ -231,9 +226,9 @@ rollback:
}
#if 0 /* NM_IGNORED */
-int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
+int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) {
+ char * const *s;
int r;
- char **s;
STRV_FOREACH(s, b) {
char *v;
@@ -352,9 +347,9 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
}
#endif /* NM_IGNORED */
-char *strv_join_prefix(char **l, const char *separator, const char *prefix) {
+char *strv_join_prefix(char * const *l, const char *separator, const char *prefix) {
+ char * const *s;
char *r, *e;
- char **s;
size_t n, k, m;
if (!separator)
@@ -568,8 +563,8 @@ char **strv_uniq(char **l) {
return l;
}
-bool strv_is_uniq(char **l) {
- char **i;
+bool strv_is_uniq(char * const *l) {
+ char * const *i;
STRV_FOREACH(i, l)
if (strv_find(i+1, *i))
@@ -674,7 +669,7 @@ char **strv_split_nulstr(const char *s) {
}
#endif /* NM_IGNORED */
-int strv_make_nulstr(char **l, char **p, size_t *q) {
+int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
/* A valid nulstr with two NULs at the end will be created, but
* q will be the length without the two trailing NULs. Thus the output
* string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
@@ -684,10 +679,10 @@ int strv_make_nulstr(char **l, char **p, size_t *q) {
size_t n_allocated = 0, n = 0;
_cleanup_free_ char *m = NULL;
- char **i;
+ char * const *i;
- assert(p);
- assert(q);
+ assert(ret);
+ assert(ret_size);
STRV_FOREACH(i, l) {
size_t z;
@@ -711,16 +706,16 @@ int strv_make_nulstr(char **l, char **p, size_t *q) {
m[n] = '\0';
assert(n > 0);
- *p = m;
- *q = n - 1;
+ *ret = m;
+ *ret_size = n - 1;
m = NULL;
return 0;
}
-bool strv_overlap(char **a, char **b) {
- char **i;
+bool strv_overlap(char * const *a, char * const *b) {
+ char * const *i;
STRV_FOREACH(i, a)
if (strv_contains(b, *i))
@@ -740,23 +735,30 @@ char **strv_sort(char **l) {
}
#endif /* NM_IGNORED */
-bool strv_equal(char **a, char **b) {
+int strv_compare(char * const *a, char * const *b) {
+ int r;
- if (strv_isempty(a))
- return strv_isempty(b);
+ if (strv_isempty(a)) {
+ if (strv_isempty(b))
+ return 0;
+ else
+ return -1;
+ }
if (strv_isempty(b))
- return false;
+ return 1;
- for ( ; *a || *b; ++a, ++b)
- if (!streq_ptr(*a, *b))
- return false;
+ for ( ; *a || *b; ++a, ++b) {
+ r = strcmp_ptr(*a, *b);
+ if (r != 0)
+ return r;
+ }
- return true;
+ return 0;
}
-void strv_print(char **l) {
- char **s;
+void strv_print(char * const *l) {
+ char * const *s;
STRV_FOREACH(s, l)
puts(*s);
@@ -810,12 +812,13 @@ char **strv_shell_escape(char **l, const char *bad) {
return l;
}
-bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
- char* const* p;
-
- STRV_FOREACH(p, patterns)
- if (fnmatch(*p, s, flags) == 0)
+bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos) {
+ for (size_t i = 0; patterns && patterns[i]; i++)
+ if (fnmatch(patterns[i], s, flags) == 0) {
+ if (matched_pos)
+ *matched_pos = i;
return true;
+ }
return false;
}
@@ -884,9 +887,9 @@ rollback:
return -ENOMEM;
}
-int fputstrv(FILE *f, char **l, const char *separator, bool *space) {
+int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
bool b = false;
- char **s;
+ char * const *s;
int r;
/* Like fputs(), but for strv, and with a less stupid argument order */
diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h
index fbfa96a566..e7c2b1a604 100644
--- a/shared/systemd/src/basic/strv.h
+++ b/shared/systemd/src/basic/strv.h
@@ -13,9 +13,9 @@
#include "macro.h"
#include "string-util.h"
-char *strv_find(char **l, const char *name) _pure_;
-char *strv_find_prefix(char **l, const char *name) _pure_;
-char *strv_find_startswith(char **l, const char *name) _pure_;
+char *strv_find(char * const *l, const char *name) _pure_;
+char *strv_find_prefix(char * const *l, const char *name) _pure_;
+char *strv_find_startswith(char * const *l, const char *name) _pure_;
char **strv_free(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
@@ -25,13 +25,11 @@ char **strv_free_erase(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep)
-void strv_clear(char **l);
-
char **strv_copy(char * const *l);
size_t strv_length(char * const *l) _pure_;
-int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
-int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
+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_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);
@@ -49,9 +47,12 @@ int strv_consume_prepend(char ***l, char *value);
char **strv_remove(char **l, const char *s);
char **strv_uniq(char **l);
-bool strv_is_uniq(char **l);
+bool strv_is_uniq(char * const *l);
-bool strv_equal(char **a, char **b);
+int strv_compare(char * const *a, char * const *b);
+static inline bool strv_equal(char * const *a, char * const *b) {
+ return strv_compare(a, b) == 0;
+}
#define strv_contains(l, s) (!!strv_find((l), (s)))
@@ -77,16 +78,16 @@ char **strv_split_newlines(const char *s);
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
-char *strv_join_prefix(char **l, const char *separator, const char *prefix);
-static inline char *strv_join(char **l, const char *separator) {
+char *strv_join_prefix(char * const *l, const char *separator, const char *prefix);
+static inline char *strv_join(char * const *l, const char *separator) {
return strv_join_prefix(l, separator, NULL);
}
char **strv_parse_nulstr(const char *s, size_t l);
char **strv_split_nulstr(const char *s);
-int strv_make_nulstr(char **l, char **p, size_t *n);
+int strv_make_nulstr(char * const *l, char **p, size_t *n);
-bool strv_overlap(char **a, char **b) _pure_;
+bool strv_overlap(char * const *a, char * const *b) _pure_;
#define STRV_FOREACH(s, l) \
for ((s) = (l); (s) && *(s); (s)++)
@@ -103,7 +104,7 @@ bool strv_overlap(char **a, char **b) _pure_;
for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
char **strv_sort(char **l);
-void strv_print(char **l);
+void strv_print(char * const *l);
#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
@@ -177,12 +178,15 @@ void strv_print(char **l);
char **strv_reverse(char **l);
char **strv_shell_escape(char **l, const char *bad);
-bool strv_fnmatch(char* const* patterns, const char *s, int flags);
+bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos);
+static inline bool strv_fnmatch(char* const* patterns, const char *s) {
+ return strv_fnmatch_full(patterns, s, 0, NULL);
+}
static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
assert(s);
return strv_isempty(patterns) ||
- strv_fnmatch(patterns, s, flags);
+ strv_fnmatch_full(patterns, s, flags, NULL);
}
char ***strv_free_free(char ***l);
@@ -192,7 +196,7 @@ char **strv_skip(char **l, size_t n);
int strv_extend_n(char ***l, const char *value, size_t n);
-int fputstrv(FILE *f, char **l, const char *separator, bool *space);
+int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
#define strv_free_and_replace(a, b) \
({ \
diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c
index 4411127a1d..71af4f21f0 100644
--- a/shared/systemd/src/basic/time-util.c
+++ b/shared/systemd/src/basic/time-util.c
@@ -1507,9 +1507,30 @@ int time_change_fd(void) {
if (fd < 0)
return -errno;
- if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0)
- return -errno;
+ if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) >= 0)
+ return TAKE_FD(fd);
+
+ /* So apparently there are systems where time_t is 64bit, but the kernel actually doesn't support
+ * 64bit time_t. In that case configuring a timer to TIME_T_MAX will fail with EOPNOTSUPP or a
+ * similar error. If that's the case let's try with INT32_MAX instead, maybe that works. It's a bit
+ * of a black magic thing though, but what can we do?
+ *
+ * We don't want this code on x86-64, hence let's conditionalize this for systems with 64bit time_t
+ * but where "long" is shorter than 64bit, i.e. 32bit archs.
+ *
+ * See: https://github.com/systemd/systemd/issues/14362 */
+
+#if SIZEOF_TIME_T == 8 && ULONG_MAX < UINT64_MAX
+ if (ERRNO_IS_NOT_SUPPORTED(errno) || errno == EOVERFLOW) {
+ static const struct itimerspec its32 = {
+ .it_value.tv_sec = INT32_MAX,
+ };
+
+ if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its32, NULL) >= 0)
+ return TAKE_FD(fd);
+ }
+#endif
- return TAKE_FD(fd);
+ return -errno;
}
#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/user-util.h b/shared/systemd/src/basic/user-util.h
new file mode 100644
index 0000000000..562f2c5ce1
--- /dev/null
+++ b/shared/systemd/src/basic/user-util.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <grp.h>
+#if ENABLE_GSHADOW
+#include <gshadow.h>
+#endif
+#include <pwd.h>
+#include <shadow.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+bool uid_is_valid(uid_t uid);
+
+static inline bool gid_is_valid(gid_t gid) {
+ return uid_is_valid((uid_t) gid);
+}
+
+int parse_uid(const char *s, uid_t* ret_uid);
+int parse_uid_range(const char *s, uid_t *ret_lower, uid_t *ret_upper);
+
+static inline int parse_gid(const char *s, gid_t *ret_gid) {
+ return parse_uid(s, (uid_t*) ret_gid);
+}
+
+char* getlogname_malloc(void);
+char* getusername_malloc(void);
+
+typedef enum UserCredsFlags {
+ USER_CREDS_PREFER_NSS = 1 << 0, /* if set, only synthesize user records if database lacks them. Normally we bypass the userdb entirely for the records we can synthesize */
+ USER_CREDS_ALLOW_MISSING = 1 << 1, /* if a numeric UID string is resolved, be OK if there's no record for it */
+ USER_CREDS_CLEAN = 1 << 2, /* try to clean up shell and home fields with invalid data */
+} UserCredsFlags;
+
+int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell, UserCredsFlags flags);
+int get_group_creds(const char **groupname, gid_t *gid, UserCredsFlags flags);
+
+char* uid_to_name(uid_t uid);
+char* gid_to_name(gid_t gid);
+
+int in_gid(gid_t gid);
+int in_group(const char *name);
+
+int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t size2, gid_t **result);
+int getgroups_alloc(gid_t** gids);
+
+int get_home_dir(char **ret);
+int get_shell(char **_ret);
+
+int reset_uid_gid(void);
+
+int take_etc_passwd_lock(const char *root);
+
+#define UID_INVALID ((uid_t) -1)
+#define GID_INVALID ((gid_t) -1)
+
+#define UID_NOBODY ((uid_t) 65534U)
+#define GID_NOBODY ((gid_t) 65534U)
+
+#define ETC_PASSWD_LOCK_PATH "/etc/.pwd.lock"
+
+#if 0 /* NM_ENABLED */
+static inline bool uid_is_system(uid_t uid) {
+ return uid <= SYSTEM_UID_MAX;
+}
+
+static inline bool gid_is_system(gid_t gid) {
+ return gid <= SYSTEM_GID_MAX;
+}
+
+static inline bool uid_is_dynamic(uid_t uid) {
+ return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
+}
+
+static inline bool gid_is_dynamic(gid_t gid) {
+ return uid_is_dynamic((uid_t) gid);
+}
+
+static inline bool uid_is_container(uid_t uid) {
+ return CONTAINER_UID_BASE_MIN <= uid && uid <= CONTAINER_UID_BASE_MAX;
+}
+
+static inline bool gid_is_container(gid_t gid) {
+ return uid_is_container((uid_t) gid);
+}
+#endif /* NM_ENABLED */
+
+/* The following macros add 1 when converting things, since UID 0 is a valid UID, while the pointer
+ * NULL is special */
+#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
+#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
+
+#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
+#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
+
+static inline bool userns_supported(void) {
+ return access("/proc/self/uid_map", F_OK) >= 0;
+}
+
+bool valid_user_group_name_full(const char *u, bool strict);
+bool valid_user_group_name_or_id_full(const char *u, bool strict);
+static inline bool valid_user_group_name(const char *u) {
+ return valid_user_group_name_full(u, true);
+}
+static inline bool valid_user_group_name_or_id(const char *u) {
+ return valid_user_group_name_or_id_full(u, true);
+}
+static inline bool valid_user_group_name_compat(const char *u) {
+ return valid_user_group_name_full(u, false);
+}
+static inline bool valid_user_group_name_or_id_compat(const char *u) {
+ return valid_user_group_name_or_id_full(u, false);
+}
+bool valid_gecos(const char *d);
+bool valid_home(const char *p);
+
+static inline bool valid_shell(const char *p) {
+ /* We have the same requirements, so just piggy-back on the home check.
+ *
+ * Let's ignore /etc/shells because this is only applicable to real and
+ * not system users. It is also incompatible with the idea of empty /etc.
+ */
+ return valid_home(p);
+}
+
+int maybe_setgroups(size_t size, const gid_t *list);
+
+bool synthesize_nobody(void);
+
+int fgetpwent_sane(FILE *stream, struct passwd **pw);
+int fgetspent_sane(FILE *stream, struct spwd **sp);
+int fgetgrent_sane(FILE *stream, struct group **gr);
+int putpwent_sane(const struct passwd *pw, FILE *stream);
+int putspent_sane(const struct spwd *sp, FILE *stream);
+int putgrent_sane(const struct group *gr, FILE *stream);
+#if ENABLE_GSHADOW
+int fgetsgent_sane(FILE *stream, struct sgrp **sg);
+int putsgent_sane(const struct sgrp *sg, FILE *stream);
+#endif
+
+bool is_nologin_shell(const char *shell);
diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c
index 7d22e7545c..94a6236a57 100644
--- a/src/systemd/src/libsystemd-network/network-internal.c
+++ b/src/systemd/src/libsystemd-network/network-internal.c
@@ -10,6 +10,7 @@
#include "sd-ndisc.h"
#include "alloc-util.h"
+#include "arphrd-list.h"
#include "condition.h"
#include "conf-parser.h"
#include "device-util.h"
@@ -106,6 +107,18 @@ static bool net_condition_test_strv(char * const *patterns, const char *string)
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;
@@ -157,7 +170,29 @@ static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = {
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_types,
@@ -166,20 +201,24 @@ bool net_match_config(Set *match_mac,
char * const *match_wifi_iftype,
char * const *match_ssid,
Set *match_bssid,
+ unsigned short iftype,
sd_device *device,
const struct ether_addr *dev_mac,
+ const struct ether_addr *dev_permanent_mac,
const char *dev_name,
+ char * const *alternative_names,
enum nl80211_iftype wifi_iftype,
const char *ssid,
const struct ether_addr *bssid) {
- const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
+ const char *dev_path = NULL, *dev_driver = NULL, *mac_str;
+ _cleanup_free_ char *dev_type;
+
+ dev_type = link_get_type_string(iftype, device);
if (device) {
(void) sd_device_get_property_value(device, "ID_PATH", &dev_path);
(void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
- (void) sd_device_get_devtype(device, &dev_type);
-
if (!dev_name)
(void) sd_device_get_sysname(device, &dev_name);
if (!dev_mac &&
@@ -190,6 +229,12 @@ bool net_match_config(Set *match_mac,
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;
@@ -199,7 +244,7 @@ bool net_match_config(Set *match_mac,
if (!net_condition_test_strv(match_types, dev_type))
return false;
- if (!net_condition_test_strv(match_names, dev_name))
+ if (!net_condition_test_ifname(match_names, dev_name, alternative_names))
return false;
if (!net_condition_test_property(match_property, device))
@@ -352,7 +397,7 @@ int config_parse_match_ifnames(
return 0;
}
- if (!ifname_valid(word)) {
+ 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;
diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h
index 2eb0cba5b7..ca850f1ac6 100644
--- a/src/systemd/src/libsystemd-network/network-internal.h
+++ b/src/systemd/src/libsystemd-network/network-internal.h
@@ -17,6 +17,7 @@
#if 0 /* NM_IGNORED */
bool net_match_config(Set *match_mac,
+ Set *match_permanent_mac,
char * const *match_path,
char * const *match_driver,
char * const *match_type,
@@ -25,9 +26,12 @@ bool net_match_config(Set *match_mac,
char * const *match_wifi_iftype,
char * const *match_ssid,
Set *match_bssid,
+ unsigned short iftype,
sd_device *device,
const struct ether_addr *dev_mac,
+ const struct ether_addr *dev_permanent_mac,
const char *dev_name,
+ char * const *alternative_names,
enum nl80211_iftype wifi_iftype,
const char *ssid,
const struct ether_addr *bssid);
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
index 0266161d78..405213ef2c 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
@@ -91,7 +91,8 @@ struct sd_dhcp_client {
usec_t start_time;
uint64_t attempt;
uint64_t max_attempts;
- OrderedHashmap *options;
+ OrderedHashmap *extra_options;
+ OrderedHashmap *vendor_options;
usec_t request_sent;
sd_event_source *timeout_t1;
sd_event_source *timeout_t2;
@@ -545,17 +546,17 @@ int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempt
return 0;
}
-int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
+int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) {
int r;
assert_return(client, -EINVAL);
assert_return(v, -EINVAL);
- r = ordered_hashmap_ensure_allocated(&client->options, &dhcp_option_hash_ops);
+ r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp_option_hash_ops);
if (r < 0)
return r;
- r = ordered_hashmap_put(client->options, UINT_TO_PTR(v->option), v);
+ r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
if (r < 0)
return r;
@@ -563,6 +564,25 @@ int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
return 0;
}
+int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) {
+ int r;
+
+ assert_return(client, -EINVAL);
+ assert_return(v, -EINVAL);
+
+ r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops);
+ if (r < 0)
+ return -ENOMEM;
+
+ r = ordered_hashmap_put(client->vendor_options, v, v);
+ if (r < 0)
+ return r;
+
+ sd_dhcp_option_ref(v);
+
+ return 1;
+}
+
int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
assert_return(client, -EINVAL);
@@ -648,7 +668,7 @@ static int client_message_init(
assert(ret);
assert(_optlen);
assert(_optoffset);
- assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE));
+ assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE, DHCP_DECLINE));
optlen = DHCP_MIN_OPTIONS_SIZE;
size = sizeof(DHCPPacket) + optlen;
@@ -889,13 +909,22 @@ static int client_send_discover(sd_dhcp_client *client) {
return r;
}
- ORDERED_HASHMAP_FOREACH(j, client->options, i) {
+ ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
j->option, j->length, j->data);
if (r < 0)
return r;
}
+ if (!ordered_hashmap_isempty(client->vendor_options)) {
+ r = dhcp_option_append(
+ &discover->dhcp, optlen, &optoffset, 0,
+ SD_DHCP_OPTION_VENDOR_SPECIFIC,
+ ordered_hashmap_size(client->vendor_options), client->vendor_options);
+ if (r < 0)
+ return r;
+ }
+
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
@@ -1971,6 +2000,48 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) {
return 0;
}
+int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
+ assert_return(client, -EINVAL);
+ assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
+ assert_return(client->lease, -EUNATCH);
+
+ _cleanup_free_ DHCPPacket *release = NULL;
+ size_t optoffset, optlen;
+ int r;
+
+ r = client_message_init(client, &release, DHCP_DECLINE, &optlen, &optoffset);
+ if (r < 0)
+ return r;
+
+ release->dhcp.ciaddr = client->lease->address;
+ memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
+
+ r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
+ SD_DHCP_OPTION_END, 0, NULL);
+ if (r < 0)
+ return r;
+
+ r = dhcp_network_send_udp_socket(client->fd,
+ client->lease->server_address,
+ DHCP_PORT_SERVER,
+ &release->dhcp,
+ sizeof(DHCPMessage) + optoffset);
+ if (r < 0)
+ return r;
+
+ log_dhcp_client(client, "DECLINE");
+
+ client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
+
+ if (client->state != DHCP_STATE_STOPPED) {
+ r = sd_dhcp_client_start(client);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
int sd_dhcp_client_stop(sd_dhcp_client *client) {
DHCP_CLIENT_DONT_DESTROY(client);
@@ -2036,7 +2107,8 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
free(client->hostname);
free(client->vendor_class_identifier);
client->user_class = strv_free(client->user_class);
- ordered_hashmap_free(client->options);
+ ordered_hashmap_free(client->extra_options);
+ ordered_hashmap_free(client->vendor_options);
return mfree(client);
}
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
index e1150f9806..e612b33b12 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -681,8 +681,7 @@ static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void
}
static usec_t client_timeout_compute_random(usec_t val) {
- return val - val / 10 +
- (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
+ return val - (random_u32() % USEC_PER_SEC) * val / 10 / USEC_PER_SEC;
}
static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) {
@@ -692,7 +691,6 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
usec_t max_retransmit_duration = 0;
uint8_t max_retransmit_count = 0;
char time_string[FORMAT_TIMESPAN_MAX];
- uint32_t expire = 0;
assert(s);
assert(client);
@@ -741,8 +739,9 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
max_retransmit_time = DHCP6_REB_MAX_RT;
if (event_source_is_enabled(client->timeout_resend_expire) <= 0) {
- r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
- &expire);
+ uint32_t expire = 0;
+
+ r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, &expire);
if (r < 0) {
client_stop(client, r);
return 0;
@@ -757,7 +756,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
return 0;
}
- if (max_retransmit_count &&
+ if (max_retransmit_count > 0 &&
client->retransmit_count >= max_retransmit_count) {
client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
return 0;
@@ -771,7 +770,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
if (r >= 0)
client->retransmit_count++;
- if (!client->retransmit_time) {
+ if (client->retransmit_time == 0) {
client->retransmit_time =
client_timeout_compute_random(init_retransmit_time);
@@ -779,7 +778,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
client->retransmit_time += init_retransmit_time / 10;
} else {
- if (max_retransmit_time &&
+ if (max_retransmit_time > 0 &&
client->retransmit_time > max_retransmit_time / 2)
client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
else
@@ -797,7 +796,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
if (r < 0)
goto error;
- if (max_retransmit_duration && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
+ if (max_retransmit_duration > 0 && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
max_retransmit_duration / USEC_PER_SEC);
diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c
index 8ffaa75d51..3e56e80780 100644
--- a/src/systemd/src/libsystemd/sd-event/sd-event.c
+++ b/src/systemd/src/libsystemd/sd-event/sd-event.c
@@ -117,6 +117,9 @@ struct sd_event {
unsigned n_sources;
+ struct epoll_event *event_queue;
+ size_t event_queue_allocated;
+
LIST_HEAD(sd_event_source, sources);
usec_t last_run, last_log;
@@ -288,6 +291,8 @@ static sd_event *event_free(sd_event *e) {
hashmap_free(e->child_sources);
set_free(e->post_sources);
+ free(e->event_queue);
+
return mfree(e);
}
@@ -388,22 +393,20 @@ static int source_io_register(
int enabled,
uint32_t events) {
- struct epoll_event ev;
- int r;
-
assert(s);
assert(s->type == SOURCE_IO);
assert(enabled != SD_EVENT_OFF);
- ev = (struct epoll_event) {
+ struct epoll_event ev = {
.events = events | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
.data.ptr = s,
};
+ int r;
- if (s->io.registered)
- r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev);
- else
- r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev);
+ r = epoll_ctl(s->event->epoll_fd,
+ s->io.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD,
+ s->io.fd,
+ &ev);
if (r < 0)
return -errno;
@@ -438,9 +441,7 @@ static int source_child_pidfd_register(sd_event_source *s, int enabled) {
assert(enabled != SD_EVENT_OFF);
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
- struct epoll_event ev;
-
- ev = (struct epoll_event) {
+ struct epoll_event ev = {
.events = EPOLLIN | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
.data.ptr = s,
};
@@ -546,7 +547,6 @@ static int event_make_signal_data(
int sig,
struct signal_data **ret) {
- struct epoll_event ev;
struct signal_data *d;
bool added = false;
sigset_t ss_copy;
@@ -613,7 +613,7 @@ static int event_make_signal_data(
d->fd = fd_move_above_stdio(r);
- ev = (struct epoll_event) {
+ struct epoll_event ev = {
.events = EPOLLIN,
.data.ptr = d,
};
@@ -825,9 +825,7 @@ static void source_disconnect(sd_event_source *s) {
if (s->prepare)
prioq_remove(s->event->prepare, s, &s->prepare_index);
- event = s->event;
-
- s->event = NULL;
+ event = TAKE_PTR(s->event);
LIST_REMOVE(sources, event->sources, s);
event->n_sources--;
@@ -1041,33 +1039,31 @@ static int event_setup_timer_fd(
struct clock_data *d,
clockid_t clock) {
- struct epoll_event ev;
- int r, fd;
-
assert(e);
assert(d);
if (_likely_(d->fd >= 0))
return 0;
+ _cleanup_close_ int fd = -1;
+ int r;
+
fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC);
if (fd < 0)
return -errno;
fd = fd_move_above_stdio(fd);
- ev = (struct epoll_event) {
+ struct epoll_event ev = {
.events = EPOLLIN,
.data.ptr = d,
};
r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
- if (r < 0) {
- safe_close(fd);
+ if (r < 0)
return -errno;
- }
- d->fd = fd;
+ d->fd = TAKE_FD(fd);
return 0;
}
@@ -1553,7 +1549,6 @@ static int event_make_inotify_data(
_cleanup_close_ int fd = -1;
struct inotify_data *d;
- struct epoll_event ev;
int r;
assert(e);
@@ -1592,7 +1587,7 @@ static int event_make_inotify_data(
return r;
}
- ev = (struct epoll_event) {
+ struct epoll_event ev = {
.events = EPOLLIN,
.data.ptr = d,
};
@@ -3481,8 +3476,7 @@ pending:
}
_public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
- struct epoll_event *ev_queue;
- unsigned ev_queue_max;
+ size_t event_queue_max;
int r, m, i;
assert_return(e, -EINVAL);
@@ -3496,14 +3490,15 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
return 1;
}
- ev_queue_max = MAX(e->n_sources, 1u);
- ev_queue = newa(struct epoll_event, ev_queue_max);
+ event_queue_max = MAX(e->n_sources, 1u);
+ if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, event_queue_max))
+ return -ENOMEM;
/* If we still have inotify data buffered, then query the other fds, but don't wait on it */
if (e->inotify_data_buffered)
timeout = 0;
- m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
+ m = epoll_wait(e->epoll_fd, e->event_queue, event_queue_max,
timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC));
if (m < 0) {
if (errno == EINTR) {
@@ -3519,26 +3514,26 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
for (i = 0; i < m; i++) {
- if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
- r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL);
+ if (e->event_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
+ r = flush_timer(e, e->watchdog_fd, e->event_queue[i].events, NULL);
else {
- WakeupType *t = ev_queue[i].data.ptr;
+ WakeupType *t = e->event_queue[i].data.ptr;
switch (*t) {
case WAKEUP_EVENT_SOURCE: {
- sd_event_source *s = ev_queue[i].data.ptr;
+ sd_event_source *s = e->event_queue[i].data.ptr;
assert(s);
switch (s->type) {
case SOURCE_IO:
- r = process_io(e, s, ev_queue[i].events);
+ r = process_io(e, s, e->event_queue[i].events);
break;
case SOURCE_CHILD:
- r = process_pidfd(e, s, ev_queue[i].events);
+ r = process_pidfd(e, s, e->event_queue[i].events);
break;
default:
@@ -3549,20 +3544,20 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
}
case WAKEUP_CLOCK_DATA: {
- struct clock_data *d = ev_queue[i].data.ptr;
+ struct clock_data *d = e->event_queue[i].data.ptr;
assert(d);
- r = flush_timer(e, d->fd, ev_queue[i].events, &d->next);
+ r = flush_timer(e, d->fd, e->event_queue[i].events, &d->next);
break;
}
case WAKEUP_SIGNAL_DATA:
- r = process_signal(e, ev_queue[i].data.ptr, ev_queue[i].events);
+ r = process_signal(e, e->event_queue[i].data.ptr, e->event_queue[i].events);
break;
case WAKEUP_INOTIFY_DATA:
- r = event_inotify_data_read(e, ev_queue[i].data.ptr, ev_queue[i].events);
+ r = event_inotify_data_read(e, e->event_queue[i].data.ptr, e->event_queue[i].events);
break;
default:
@@ -3846,8 +3841,6 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
return e->watchdog;
if (b) {
- struct epoll_event ev;
-
r = sd_watchdog_enabled(false, &e->watchdog_period);
if (r <= 0)
return r;
@@ -3864,7 +3857,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
if (r < 0)
goto fail;
- ev = (struct epoll_event) {
+ struct epoll_event ev = {
.events = EPOLLIN,
.data.ptr = INT_TO_PTR(SOURCE_WATCHDOG),
};
diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c
index 11ae9037a3..3cb963786e 100644
--- a/src/systemd/src/libsystemd/sd-id128/id128-util.c
+++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c
@@ -195,5 +195,18 @@ int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
return memcmp(a, b, 16);
}
+sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
+ /* Stolen from generate_random_uuid() of drivers/char/random.c
+ * in the kernel sources */
+
+ /* Set UUID version to 4 --- truly random generation */
+ id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
+
+ /* Set the UUID variant to DCE */
+ id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
+
+ return id;
+}
+
DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
#endif /* NM_IGNORED */
diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h
index fe0149a8aa..1901bf119f 100644
--- a/src/systemd/src/libsystemd/sd-id128/id128-util.h
+++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h
@@ -30,3 +30,5 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
extern const struct hash_ops id128_hash_ops;
+
+sd_id128_t id128_make_v4_uuid(sd_id128_t id);
diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
index c0d0fe8188..d585ff2596 100644
--- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
@@ -255,19 +255,6 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
return 0;
}
-static sd_id128_t make_v4_uuid(sd_id128_t id) {
- /* Stolen from generate_random_uuid() of drivers/char/random.c
- * in the kernel sources */
-
- /* Set UUID version to 4 --- truly random generation */
- id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
-
- /* Set the UUID variant to DCE */
- id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
-
- return id;
-}
-
_public_ int sd_id128_randomize(sd_id128_t *ret) {
sd_id128_t t;
int r;
@@ -284,7 +271,7 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
* only guarantee this for newly generated UUIDs, not for
* pre-existing ones. */
- *ret = make_v4_uuid(t);
+ *ret = id128_make_v4_uuid(t);
return 0;
}
@@ -311,7 +298,7 @@ static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret)
/* We chop off the trailing 16 bytes */
memcpy(&result, p, MIN(khash_get_size(h), sizeof(result)));
- *ret = make_v4_uuid(result);
+ *ret = id128_make_v4_uuid(result);
return 0;
}
diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h
index b3ee7bbc24..8158ee733e 100644
--- a/src/systemd/src/systemd/_sd-common.h
+++ b/src/systemd/src/systemd/_sd-common.h
@@ -45,6 +45,18 @@ typedef void (*_sd_destroy_t)(void *userdata);
# define _sd_pure_ __attribute__((__pure__))
#endif
+/* Note that strictly speaking __deprecated__ has been available before GCC 6. However, starting with GCC 6
+ * it also works on enum values, which we are interested in. Since this is a developer-facing feature anyway
+ * (as opposed to build engineer-facing), let's hence conditionalize this to gcc 6, given that the developers
+ * are probably going to use something newer anyway. */
+#ifndef _sd_deprecated_
+# if __GNUC__ >= 6
+# define _sd_deprecated_ __attribute__((__deprecated__))
+# else
+# define _sd_deprecated_
+# endif
+#endif
+
#ifndef _SD_STRINGIFY
# define _SD_XSTRINGIFY(x) #x
# define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x)
diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h
index f97e35b654..9dd562fa43 100644
--- a/src/systemd/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/src/systemd/sd-dhcp-client.h
@@ -179,11 +179,13 @@ int sd_dhcp_client_set_service_type(
sd_dhcp_client *client,
int type);
-int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v);
+int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
+int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
int sd_dhcp_client_stop(sd_dhcp_client *client);
int sd_dhcp_client_start(sd_dhcp_client *client);
int sd_dhcp_client_send_release(sd_dhcp_client *client);
+int sd_dhcp_client_send_decline(sd_dhcp_client *client);
int sd_dhcp_client_send_renew(sd_dhcp_client *client);
sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);