summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-12-23 00:46:32 +0100
committerThomas Haller <thaller@redhat.com>2018-12-23 11:42:32 +0100
commit9e9320cc0f09f1066afe49568c13feda90bcf1be (patch)
tree26979828f747e03f9e20bc6b116274182e157ad3
parentbf604ae2d8d57b2087c7358e54a1fe7867d11f11 (diff)
parentc2dbe4b5f77aaed1f00fab69bd5ebaa9cc8fce30 (diff)
downloadNetworkManager-9e9320cc0f09f1066afe49568c13feda90bcf1be.tar.gz
systemd: merge branch systemd into master
-rw-r--r--Makefile.am9
-rw-r--r--src/systemd/meson.build2
-rw-r--r--src/systemd/sd-adapt/dirent-util.h2
-rw-r--r--src/systemd/sd-adapt/missing_socket.h3
-rw-r--r--src/systemd/sd-adapt/missing_syscall.h3
-rw-r--r--src/systemd/sd-adapt/missing_timerfd.h3
-rw-r--r--src/systemd/sd-adapt/missing_type.h3
-rw-r--r--src/systemd/sd-adapt/rlimit-util.h3
-rw-r--r--src/systemd/src/basic/alloc-util.c2
-rw-r--r--src/systemd/src/basic/alloc-util.h8
-rw-r--r--src/systemd/src/basic/env-file.c578
-rw-r--r--src/systemd/src/basic/env-file.h17
-rw-r--r--src/systemd/src/basic/escape.h2
-rw-r--r--src/systemd/src/basic/ether-addr-util.c12
-rw-r--r--src/systemd/src/basic/ether-addr-util.h2
-rw-r--r--src/systemd/src/basic/fd-util.c5
-rw-r--r--src/systemd/src/basic/fileio.c1068
-rw-r--r--src/systemd/src/basic/fileio.h36
-rw-r--r--src/systemd/src/basic/fs-util.c108
-rw-r--r--src/systemd/src/basic/fs-util.h1
-rw-r--r--src/systemd/src/basic/hash-funcs.c51
-rw-r--r--src/systemd/src/basic/hash-funcs.h77
-rw-r--r--src/systemd/src/basic/hashmap.c92
-rw-r--r--src/systemd/src/basic/hashmap.h56
-rw-r--r--src/systemd/src/basic/hostname-util.c56
-rw-r--r--src/systemd/src/basic/hostname-util.h1
-rw-r--r--src/systemd/src/basic/in-addr-util.c14
-rw-r--r--src/systemd/src/basic/in-addr-util.h2
-rw-r--r--src/systemd/src/basic/list.h6
-rw-r--r--src/systemd/src/basic/macro.h68
-rw-r--r--src/systemd/src/basic/parse-util.c50
-rw-r--r--src/systemd/src/basic/parse-util.h1
-rw-r--r--src/systemd/src/basic/path-util.c112
-rw-r--r--src/systemd/src/basic/path-util.h40
-rw-r--r--src/systemd/src/basic/prioq.c11
-rw-r--r--src/systemd/src/basic/process-util.c89
-rw-r--r--src/systemd/src/basic/process-util.h19
-rw-r--r--src/systemd/src/basic/random-util.c1
-rw-r--r--src/systemd/src/basic/set.h10
-rw-r--r--src/systemd/src/basic/socket-util.c103
-rw-r--r--src/systemd/src/basic/socket-util.h13
-rw-r--r--src/systemd/src/basic/stat-util.c123
-rw-r--r--src/systemd/src/basic/stat-util.h26
-rw-r--r--src/systemd/src/basic/strv.h12
-rw-r--r--src/systemd/src/basic/time-util.c5
-rw-r--r--src/systemd/src/basic/tmpfile-util.c335
-rw-r--r--src/systemd/src/basic/tmpfile-util.h19
-rw-r--r--src/systemd/src/basic/utf8.h2
-rw-r--r--src/systemd/src/basic/util.c1
-rw-r--r--src/systemd/src/basic/util.h11
-rw-r--r--src/systemd/src/libsystemd-network/lldp-neighbor.c36
-rw-r--r--src/systemd/src/libsystemd-network/lldp-neighbor.h2
-rw-r--r--src/systemd/src/libsystemd-network/lldp-network.c1
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.c30
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.h1
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-client.c33
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-lease.c4
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-client.c8
-rw-r--r--src/systemd/src/libsystemd-network/sd-lldp.c8
-rw-r--r--src/systemd/src/libsystemd/sd-event/sd-event.c14
-rw-r--r--src/systemd/src/libsystemd/sd-id128/id128-util.c11
-rw-r--r--src/systemd/src/libsystemd/sd-id128/id128-util.h4
-rw-r--r--src/systemd/src/shared/dns-domain.c111
-rw-r--r--src/systemd/src/shared/dns-domain.h32
-rw-r--r--src/systemd/src/systemd/_sd-common.h4
-rw-r--r--src/systemd/src/systemd/sd-dhcp-client.h3
-rw-r--r--src/systemd/src/systemd/sd-event.h2
-rw-r--r--src/systemd/src/systemd/sd-id128.h16
68 files changed, 2088 insertions, 1505 deletions
diff --git a/Makefile.am b/Makefile.am
index 68f4f0a28e..6b0812b6aa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1541,9 +1541,14 @@ src_libsystemd_nm_la_SOURCES = \
src/systemd/sd-adapt/locale-util.h \
src/systemd/sd-adapt/memfd-util.h \
src/systemd/sd-adapt/missing.h \
+ src/systemd/sd-adapt/missing_socket.h \
+ src/systemd/sd-adapt/missing_syscall.h \
+ src/systemd/sd-adapt/missing_timerfd.h \
+ src/systemd/sd-adapt/missing_type.h \
src/systemd/sd-adapt/mkdir.h \
src/systemd/sd-adapt/procfs-util.h \
src/systemd/sd-adapt/raw-clone.h \
+ src/systemd/sd-adapt/rlimit-util.h \
src/systemd/sd-adapt/sd-daemon.h \
src/systemd/sd-adapt/sd-device.h \
src/systemd/sd-adapt/serialize.h \
@@ -1555,6 +1560,8 @@ src_libsystemd_nm_la_SOURCES = \
src/systemd/src/basic/alloc-util.c \
src/systemd/src/basic/alloc-util.h \
src/systemd/src/basic/async.h \
+ src/systemd/src/basic/env-file.c \
+ src/systemd/src/basic/env-file.h \
src/systemd/src/basic/env-util.c \
src/systemd/src/basic/env-util.h \
src/systemd/src/basic/escape.c \
@@ -1614,6 +1621,8 @@ src_libsystemd_nm_la_SOURCES = \
src/systemd/src/basic/strv.h \
src/systemd/src/basic/time-util.c \
src/systemd/src/basic/time-util.h \
+ src/systemd/src/basic/tmpfile-util.c \
+ src/systemd/src/basic/tmpfile-util.h \
src/systemd/src/basic/umask-util.h \
src/systemd/src/basic/utf8.c \
src/systemd/src/basic/utf8.h \
diff --git a/src/systemd/meson.build b/src/systemd/meson.build
index ee9912bcfa..adeeb6800b 100644
--- a/src/systemd/meson.build
+++ b/src/systemd/meson.build
@@ -2,6 +2,7 @@ sources = files(
'sd-adapt/nm-sd-adapt.c',
'src/basic/alloc-util.c',
'src/basic/escape.c',
+ 'src/basic/env-file.c',
'src/basic/env-util.c',
'src/basic/ether-addr-util.c',
'src/basic/extract-word.c',
@@ -26,6 +27,7 @@ sources = files(
'src/basic/string-util.c',
'src/basic/strv.c',
'src/basic/time-util.c',
+ 'src/basic/tmpfile-util.c',
'src/basic/utf8.c',
'src/basic/util.c',
'src/libsystemd-network/arp-util.c',
diff --git a/src/systemd/sd-adapt/dirent-util.h b/src/systemd/sd-adapt/dirent-util.h
index 637892c2d6..7132dfcc51 100644
--- a/src/systemd/sd-adapt/dirent-util.h
+++ b/src/systemd/sd-adapt/dirent-util.h
@@ -1,3 +1,5 @@
#pragma once
/* dummy header */
+
+#include "path-util.h"
diff --git a/src/systemd/sd-adapt/missing_socket.h b/src/systemd/sd-adapt/missing_socket.h
new file mode 100644
index 0000000000..637892c2d6
--- /dev/null
+++ b/src/systemd/sd-adapt/missing_socket.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/systemd/sd-adapt/missing_syscall.h b/src/systemd/sd-adapt/missing_syscall.h
new file mode 100644
index 0000000000..637892c2d6
--- /dev/null
+++ b/src/systemd/sd-adapt/missing_syscall.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/systemd/sd-adapt/missing_timerfd.h b/src/systemd/sd-adapt/missing_timerfd.h
new file mode 100644
index 0000000000..637892c2d6
--- /dev/null
+++ b/src/systemd/sd-adapt/missing_timerfd.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/systemd/sd-adapt/missing_type.h b/src/systemd/sd-adapt/missing_type.h
new file mode 100644
index 0000000000..637892c2d6
--- /dev/null
+++ b/src/systemd/sd-adapt/missing_type.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/systemd/sd-adapt/rlimit-util.h b/src/systemd/sd-adapt/rlimit-util.h
new file mode 100644
index 0000000000..637892c2d6
--- /dev/null
+++ b/src/systemd/sd-adapt/rlimit-util.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/systemd/src/basic/alloc-util.c b/src/systemd/src/basic/alloc-util.c
index ef40509833..2e1c7ef61e 100644
--- a/src/systemd/src/basic/alloc-util.c
+++ b/src/systemd/src/basic/alloc-util.c
@@ -14,7 +14,7 @@ void* memdup(const void *p, size_t l) {
assert(l == 0 || p);
- ret = malloc(l);
+ ret = malloc(l ?: 1);
if (!ret)
return NULL;
diff --git a/src/systemd/src/basic/alloc-util.h b/src/systemd/src/basic/alloc-util.h
index 2a6deb12ca..ff7a46793a 100644
--- a/src/systemd/src/basic/alloc-util.h
+++ b/src/systemd/src/basic/alloc-util.h
@@ -8,9 +8,11 @@
#include "macro.h"
+typedef void (*free_func_t)(void *p);
+
#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
-#define new0(t, n) ((t*) calloc((n), sizeof(t)))
+#define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t)))
#define newa(t, n) \
({ \
@@ -75,7 +77,7 @@ _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t
if (size_multiply_overflow(size, need))
return NULL;
- return malloc(size * need);
+ return malloc(size * need ?: 1);
}
#if !HAVE_REALLOCARRAY
@@ -83,7 +85,7 @@ _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size
if (size_multiply_overflow(size, need))
return NULL;
- return realloc(p, size * need);
+ return realloc(p, size * need ?: 1);
}
#endif
diff --git a/src/systemd/src/basic/env-file.c b/src/systemd/src/basic/env-file.c
new file mode 100644
index 0000000000..40051c312e
--- /dev/null
+++ b/src/systemd/src/basic/env-file.c
@@ -0,0 +1,578 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "nm-sd-adapt.h"
+
+#include <stdio_ext.h>
+
+#include "alloc-util.h"
+#include "env-file.h"
+#include "env-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "tmpfile-util.h"
+#include "utf8.h"
+
+static int parse_env_file_internal(
+ FILE *f,
+ const char *fname,
+ int (*push) (const char *filename, unsigned line,
+ const char *key, char *value, void *userdata, int *n_pushed),
+ void *userdata,
+ int *n_pushed) {
+
+ size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
+ _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
+ unsigned line = 1;
+ char *p;
+ int r;
+
+ enum {
+ PRE_KEY,
+ KEY,
+ PRE_VALUE,
+ VALUE,
+ VALUE_ESCAPE,
+ SINGLE_QUOTE_VALUE,
+ SINGLE_QUOTE_VALUE_ESCAPE,
+ DOUBLE_QUOTE_VALUE,
+ DOUBLE_QUOTE_VALUE_ESCAPE,
+ COMMENT,
+ COMMENT_ESCAPE
+ } state = PRE_KEY;
+
+ if (f)
+ r = read_full_stream(f, &contents, NULL);
+ else
+ r = read_full_file(fname, &contents, NULL);
+ if (r < 0)
+ return r;
+
+ for (p = contents; *p; p++) {
+ char c = *p;
+
+ switch (state) {
+
+ case PRE_KEY:
+ if (strchr(COMMENTS, c))
+ state = COMMENT;
+ else if (!strchr(WHITESPACE, c)) {
+ state = KEY;
+ last_key_whitespace = (size_t) -1;
+
+ if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
+ return -ENOMEM;
+
+ key[n_key++] = c;
+ }
+ break;
+
+ case KEY:
+ if (strchr(NEWLINE, c)) {
+ state = PRE_KEY;
+ line++;
+ n_key = 0;
+ } else if (c == '=') {
+ state = PRE_VALUE;
+ last_value_whitespace = (size_t) -1;
+ } else {
+ if (!strchr(WHITESPACE, c))
+ last_key_whitespace = (size_t) -1;
+ else if (last_key_whitespace == (size_t) -1)
+ last_key_whitespace = n_key;
+
+ if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
+ return -ENOMEM;
+
+ key[n_key++] = c;
+ }
+
+ break;
+
+ case PRE_VALUE:
+ if (strchr(NEWLINE, c)) {
+ state = PRE_KEY;
+ line++;
+ key[n_key] = 0;
+
+ if (value)
+ value[n_value] = 0;
+
+ /* strip trailing whitespace from key */
+ if (last_key_whitespace != (size_t) -1)
+ key[last_key_whitespace] = 0;
+
+ r = push(fname, line, key, value, userdata, n_pushed);
+ if (r < 0)
+ return r;
+
+ n_key = 0;
+ value = NULL;
+ value_alloc = n_value = 0;
+
+ } else if (c == '\'')
+ state = SINGLE_QUOTE_VALUE;
+ else if (c == '\"')
+ state = DOUBLE_QUOTE_VALUE;
+ else if (c == '\\')
+ state = VALUE_ESCAPE;
+ else if (!strchr(WHITESPACE, c)) {
+ state = VALUE;
+
+ if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+ return -ENOMEM;
+
+ value[n_value++] = c;
+ }
+
+ break;
+
+ case VALUE:
+ if (strchr(NEWLINE, c)) {
+ state = PRE_KEY;
+ line++;
+
+ key[n_key] = 0;
+
+ if (value)
+ value[n_value] = 0;
+
+ /* Chomp off trailing whitespace from value */
+ if (last_value_whitespace != (size_t) -1)
+ value[last_value_whitespace] = 0;
+
+ /* strip trailing whitespace from key */
+ if (last_key_whitespace != (size_t) -1)
+ key[last_key_whitespace] = 0;
+
+ r = push(fname, line, key, value, userdata, n_pushed);
+ if (r < 0)
+ return r;
+
+ n_key = 0;
+ value = NULL;
+ value_alloc = n_value = 0;
+
+ } else if (c == '\\') {
+ state = VALUE_ESCAPE;
+ last_value_whitespace = (size_t) -1;
+ } else {
+ if (!strchr(WHITESPACE, c))
+ last_value_whitespace = (size_t) -1;
+ else if (last_value_whitespace == (size_t) -1)
+ last_value_whitespace = n_value;
+
+ if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+ return -ENOMEM;
+
+ value[n_value++] = c;
+ }
+
+ break;
+
+ case VALUE_ESCAPE:
+ state = VALUE;
+
+ if (!strchr(NEWLINE, c)) {
+ /* Escaped newlines we eat up entirely */
+ if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+ return -ENOMEM;
+
+ value[n_value++] = c;
+ }
+ break;
+
+ case SINGLE_QUOTE_VALUE:
+ if (c == '\'')
+ state = PRE_VALUE;
+ else if (c == '\\')
+ state = SINGLE_QUOTE_VALUE_ESCAPE;
+ else {
+ if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+ return -ENOMEM;
+
+ value[n_value++] = c;
+ }
+
+ break;
+
+ case SINGLE_QUOTE_VALUE_ESCAPE:
+ state = SINGLE_QUOTE_VALUE;
+
+ if (!strchr(NEWLINE, c)) {
+ if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+ return -ENOMEM;
+
+ value[n_value++] = c;
+ }
+ break;
+
+ case DOUBLE_QUOTE_VALUE:
+ if (c == '\"')
+ state = PRE_VALUE;
+ else if (c == '\\')
+ state = DOUBLE_QUOTE_VALUE_ESCAPE;
+ else {
+ if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+ return -ENOMEM;
+
+ value[n_value++] = c;
+ }
+
+ break;
+
+ case DOUBLE_QUOTE_VALUE_ESCAPE:
+ state = DOUBLE_QUOTE_VALUE;
+
+ if (!strchr(NEWLINE, c)) {
+ if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
+ return -ENOMEM;
+
+ value[n_value++] = c;
+ }
+ break;
+
+ case COMMENT:
+ if (c == '\\')
+ state = COMMENT_ESCAPE;
+ else if (strchr(NEWLINE, c)) {
+ state = PRE_KEY;
+ line++;
+ }
+ break;
+
+ case COMMENT_ESCAPE:
+ state = COMMENT;
+ break;
+ }
+ }
+
+ if (IN_SET(state,
+ PRE_VALUE,
+ VALUE,
+ VALUE_ESCAPE,
+ SINGLE_QUOTE_VALUE,
+ SINGLE_QUOTE_VALUE_ESCAPE,
+ DOUBLE_QUOTE_VALUE,
+ DOUBLE_QUOTE_VALUE_ESCAPE)) {
+
+ key[n_key] = 0;
+
+ if (value)
+ value[n_value] = 0;
+
+ if (state == VALUE)
+ if (last_value_whitespace != (size_t) -1)
+ value[last_value_whitespace] = 0;
+
+ /* strip trailing whitespace from key */
+ if (last_key_whitespace != (size_t) -1)
+ key[last_key_whitespace] = 0;
+
+ r = push(fname, line, key, value, userdata, n_pushed);
+ if (r < 0)
+ return r;
+
+ value = NULL;
+ }
+
+ return 0;
+}
+
+static int check_utf8ness_and_warn(
+ const char *filename, unsigned line,
+ const char *key, char *value) {
+
+ if (!utf8_is_valid(key)) {
+ _cleanup_free_ char *p = NULL;
+
+ p = utf8_escape_invalid(key);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s:%u: invalid UTF-8 in key '%s', ignoring.",
+ strna(filename), line, p);
+ }
+
+ if (value && !utf8_is_valid(value)) {
+ _cleanup_free_ char *p = NULL;
+
+ p = utf8_escape_invalid(value);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
+ strna(filename), line, key, p);
+ }
+
+ return 0;
+}
+
+static int parse_env_file_push(
+ const char *filename, unsigned line,
+ const char *key, char *value,
+ void *userdata,
+ int *n_pushed) {
+
+ const char *k;
+ va_list aq, *ap = userdata;
+ int r;
+
+ r = check_utf8ness_and_warn(filename, line, key, value);
+ if (r < 0)
+ return r;
+
+ va_copy(aq, *ap);
+
+ while ((k = va_arg(aq, const char *))) {
+ char **v;
+
+ v = va_arg(aq, char **);
+
+ if (streq(key, k)) {
+ va_end(aq);
+ free(*v);
+ *v = value;
+
+ if (n_pushed)
+ (*n_pushed)++;
+
+ return 1;
+ }
+ }
+
+ va_end(aq);
+ free(value);
+
+ return 0;
+}
+
+int parse_env_filev(
+ FILE *f,
+ const char *fname,
+ va_list ap) {
+
+ int r, n_pushed = 0;
+ va_list aq;
+
+ va_copy(aq, ap);
+ r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed);
+ va_end(aq);
+ if (r < 0)
+ return r;
+
+ return n_pushed;
+}
+
+int parse_env_file_sentinel(
+ FILE *f,
+ const char *fname,
+ ...) {
+
+ va_list ap;
+ int r;
+
+ va_start(ap, fname);
+ r = parse_env_filev(f, fname, ap);
+ va_end(ap);
+
+ return r;
+}
+
+#if 0 /* NM_IGNORED */
+static int load_env_file_push(
+ const char *filename, unsigned line,
+ const char *key, char *value,
+ void *userdata,
+ int *n_pushed) {
+ char ***m = userdata;
+ char *p;
+ int r;
+
+ r = check_utf8ness_and_warn(filename, line, key, value);
+ if (r < 0)
+ return r;
+
+ p = strjoin(key, "=", value);
+ if (!p)
+ return -ENOMEM;
+
+ r = strv_env_replace(m, p);
+ if (r < 0) {
+ free(p);
+ return r;
+ }
+
+ if (n_pushed)
+ (*n_pushed)++;
+
+ free(value);
+ return 0;
+}
+
+int load_env_file(FILE *f, const char *fname, char ***rl) {
+ char **m = NULL;
+ int r;
+
+ r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
+ if (r < 0) {
+ strv_free(m);
+ return r;
+ }
+
+ *rl = m;
+ return 0;
+}
+
+static int load_env_file_push_pairs(
+ const char *filename, unsigned line,
+ const char *key, char *value,
+ void *userdata,
+ int *n_pushed) {
+ char ***m = userdata;
+ int r;
+
+ r = check_utf8ness_and_warn(filename, line, key, value);
+ if (r < 0)
+ return r;
+
+ r = strv_extend(m, key);
+ if (r < 0)
+ return -ENOMEM;
+
+ if (!value) {
+ r = strv_extend(m, "");
+ if (r < 0)
+ return -ENOMEM;
+ } else {
+ r = strv_push(m, value);
+ if (r < 0)
+ return r;
+ }
+
+ if (n_pushed)
+ (*n_pushed)++;
+
+ return 0;
+}
+
+int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
+ char **m = NULL;
+ int r;
+
+ r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
+ if (r < 0) {
+ strv_free(m);
+ return r;
+ }
+
+ *rl = m;
+ return 0;
+}
+
+static int merge_env_file_push(
+ const char *filename, unsigned line,
+ const char *key, char *value,
+ void *userdata,
+ int *n_pushed) {
+
+ char ***env = userdata;
+ char *expanded_value;
+
+ assert(env);
+
+ if (!value) {
+ log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
+ return 0;
+ }
+
+ if (!env_name_is_valid(key)) {
+ log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key);
+ free(value);
+ return 0;
+ }
+
+ expanded_value = replace_env(value, *env,
+ REPLACE_ENV_USE_ENVIRONMENT|
+ REPLACE_ENV_ALLOW_BRACELESS|
+ REPLACE_ENV_ALLOW_EXTENDED);
+ if (!expanded_value)
+ return -ENOMEM;
+
+ free_and_replace(value, expanded_value);
+
+ return load_env_file_push(filename, line, key, value, env, n_pushed);
+}
+
+int merge_env_file(
+ char ***env,
+ FILE *f,
+ const char *fname) {
+
+ /* NOTE: this function supports braceful and braceless variable expansions,
+ * plus "extended" substitutions, unlike other exported parsing functions.
+ */
+
+ return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL);
+}
+
+static void write_env_var(FILE *f, const char *v) {
+ const char *p;
+
+ p = strchr(v, '=');
+ if (!p) {
+ /* Fallback */
+ fputs_unlocked(v, f);
+ fputc_unlocked('\n', f);
+ return;
+ }
+
+ p++;
+ fwrite_unlocked(v, 1, p-v, f);
+
+ if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
+ fputc_unlocked('\"', f);
+
+ for (; *p; p++) {
+ if (strchr(SHELL_NEED_ESCAPE, *p))
+ fputc_unlocked('\\', f);
+
+ fputc_unlocked(*p, f);
+ }
+
+ fputc_unlocked('\"', f);
+ } else
+ fputs_unlocked(p, f);
+
+ fputc_unlocked('\n', f);
+}
+
+int write_env_file(const char *fname, char **l) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *p = NULL;
+ char **i;
+ int r;
+
+ assert(fname);
+
+ r = fopen_temporary(fname, &f, &p);
+ if (r < 0)
+ return r;
+
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+ (void) fchmod_umask(fileno(f), 0644);
+
+ STRV_FOREACH(i, l)
+ write_env_var(f, *i);
+
+ r = fflush_and_check(f);
+ if (r >= 0) {
+ if (rename(p, fname) >= 0)
+ return 0;
+
+ r = -errno;
+ }
+
+ unlink(p);
+ return r;
+}
+#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/env-file.h b/src/systemd/src/basic/env-file.h
new file mode 100644
index 0000000000..e1ca195ff0
--- /dev/null
+++ b/src/systemd/src/basic/env-file.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "macro.h"
+
+int parse_env_filev(FILE *f, const char *fname, va_list ap);
+int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
+#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
+int load_env_file(FILE *f, const char *fname, char ***l);
+int load_env_file_pairs(FILE *f, const char *fname, char ***l);
+
+int merge_env_file(char ***env, FILE *f, const char *fname);
+
+int write_env_file(const char *fname, char **l);
diff --git a/src/systemd/src/basic/escape.h b/src/systemd/src/basic/escape.h
index c612a7c02d..cc6a897c49 100644
--- a/src/systemd/src/basic/escape.h
+++ b/src/systemd/src/basic/escape.h
@@ -10,7 +10,7 @@
#endif /* NM_IGNORED */
#include "string-util.h"
-#include "missing.h"
+#include "missing_type.h"
/* What characters are special in the shell? */
/* must be escaped outside and inside double-quotes */
diff --git a/src/systemd/src/basic/ether-addr-util.c b/src/systemd/src/basic/ether-addr-util.c
index ed92bc609c..602bbae059 100644
--- a/src/systemd/src/basic/ether-addr-util.c
+++ b/src/systemd/src/basic/ether-addr-util.c
@@ -30,21 +30,15 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR
return buffer;
}
-int ether_addr_compare(const void *a, const void *b) {
- assert(a);
- assert(b);
-
+int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b) {
return memcmp(a, b, ETH_ALEN);
}
-static void ether_addr_hash_func(const void *p, struct siphash *state) {
+static void ether_addr_hash_func(const struct ether_addr *p, struct siphash *state) {
siphash24_compress(p, sizeof(struct ether_addr), state);
}
-const struct hash_ops ether_addr_hash_ops = {
- .hash = ether_addr_hash_func,
- .compare = ether_addr_compare
-};
+DEFINE_HASH_OPS(ether_addr_hash_ops, struct ether_addr, ether_addr_hash_func, ether_addr_compare);
int ether_addr_from_string(const char *s, struct ether_addr *ret) {
size_t pos = 0, n, field;
diff --git a/src/systemd/src/basic/ether-addr-util.h b/src/systemd/src/basic/ether-addr-util.h
index 3be0370049..4e44b30be9 100644
--- a/src/systemd/src/basic/ether-addr-util.h
+++ b/src/systemd/src/basic/ether-addr-util.h
@@ -12,7 +12,7 @@
#define ETHER_ADDR_TO_STRING_MAX (3*6)
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
-int ether_addr_compare(const void *a, const void *b);
+int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b);
static inline bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
return ether_addr_compare(a, b) == 0;
}
diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c
index 6c6068038a..a242b739cd 100644
--- a/src/systemd/src/basic/fd-util.c
+++ b/src/systemd/src/basic/fd-util.c
@@ -25,6 +25,7 @@
#include "socket-util.h"
#include "stdio-util.h"
#include "util.h"
+#include "tmpfile-util.h"
int close_nointr(int fd) {
assert(fd >= 0);
@@ -115,7 +116,7 @@ FILE* safe_fclose(FILE *f) {
if (f) {
PROTECT_ERRNO;
- assert_se(fclose_nointr(f) != EBADF);
+ assert_se(fclose_nointr(f) != -EBADF);
}
return NULL;
@@ -653,7 +654,7 @@ int fd_duplicate_data_fd(int fd) {
if ((size_t) isz >= DATA_FD_MEMORY_LIMIT) {
- r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size);
+ r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size, NULL, NULL);
if (r < 0 && r != -EAGAIN)
return r; /* If we get EAGAIN it could be because of the source or because of
* the destination fd, we can't know, as sendfile() and friends won't
diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c
index d9794403a1..93b8b2439b 100644
--- a/src/systemd/src/basic/fileio.c
+++ b/src/systemd/src/basic/fileio.c
@@ -2,6 +2,7 @@
#include "nm-sd-adapt.h"
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -10,32 +11,22 @@
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "alloc-util.h"
-#include "ctype.h"
-#include "env-util.h"
-#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
-#include "hexdecoct.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
-#include "process-util.h"
-#include "random-util.h"
#include "stdio-util.h"
#include "string-util.h"
-#include "strv.h"
-#include "time-util.h"
-#include "umask-util.h"
-#include "utf8.h"
+#include "tmpfile-util.h"
#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
@@ -168,7 +159,7 @@ int write_string_file_ts(
goto fail;
}
- f = fdopen(fd, "we");
+ f = fdopen(fd, "w");
if (!f) {
r = -errno;
safe_close(fd);
@@ -279,16 +270,20 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
}
#endif /* NM_IGNORED */
-int read_full_stream(FILE *f, char **contents, size_t *size) {
+int read_full_stream(
+ FILE *f,
+ char **ret_contents,
+ size_t *ret_size) {
+
_cleanup_free_ char *buf = NULL;
struct stat st;
size_t n, l;
int fd;
assert(f);
- assert(contents);
+ assert(ret_contents);
- n = LINE_MAX;
+ n = LINE_MAX; /* Start size */
fd = fileno(f);
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's
@@ -344,11 +339,20 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
n = MIN(n * 2, READ_FULL_BYTES_MAX);
}
+ if (!ret_size) {
+ /* Safety check: if the caller doesn't want to know the size of what we just read it will rely on the
+ * trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise
+ * there'd be ambiguity about what we just read. */
+
+ if (memchr(buf, 0, l))
+ return -EBADMSG;
+ }
+
buf[l] = 0;
- *contents = TAKE_PTR(buf);
+ *ret_contents = TAKE_PTR(buf);
- if (size)
- *size = l;
+ if (ret_size)
+ *ret_size = l;
return 0;
}
@@ -368,566 +372,7 @@ int read_full_file(const char *fn, char **contents, size_t *size) {
return read_full_stream(f, contents, size);
}
-static int parse_env_file_internal(
- FILE *f,
- const char *fname,
- int (*push) (const char *filename, unsigned line,
- const char *key, char *value, void *userdata, int *n_pushed),
- void *userdata,
- int *n_pushed) {
-
- size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
- _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
- unsigned line = 1;
- char *p;
- int r;
-
- enum {
- PRE_KEY,
- KEY,
- PRE_VALUE,
- VALUE,
- VALUE_ESCAPE,
- SINGLE_QUOTE_VALUE,
- SINGLE_QUOTE_VALUE_ESCAPE,
- DOUBLE_QUOTE_VALUE,
- DOUBLE_QUOTE_VALUE_ESCAPE,
- COMMENT,
- COMMENT_ESCAPE
- } state = PRE_KEY;
-
- if (f)
- r = read_full_stream(f, &contents, NULL);
- else
- r = read_full_file(fname, &contents, NULL);
- if (r < 0)
- return r;
-
- for (p = contents; *p; p++) {
- char c = *p;
-
- switch (state) {
-
- case PRE_KEY:
- if (strchr(COMMENTS, c))
- state = COMMENT;
- else if (!strchr(WHITESPACE, c)) {
- state = KEY;
- last_key_whitespace = (size_t) -1;
-
- if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
- return -ENOMEM;
-
- key[n_key++] = c;
- }
- break;
-
- case KEY:
- if (strchr(NEWLINE, c)) {
- state = PRE_KEY;
- line++;
- n_key = 0;
- } else if (c == '=') {
- state = PRE_VALUE;
- last_value_whitespace = (size_t) -1;
- } else {
- if (!strchr(WHITESPACE, c))
- last_key_whitespace = (size_t) -1;
- else if (last_key_whitespace == (size_t) -1)
- last_key_whitespace = n_key;
-
- if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
- return -ENOMEM;
-
- key[n_key++] = c;
- }
-
- break;
-
- case PRE_VALUE:
- if (strchr(NEWLINE, c)) {
- state = PRE_KEY;
- line++;
- key[n_key] = 0;
-
- if (value)
- value[n_value] = 0;
-
- /* strip trailing whitespace from key */
- if (last_key_whitespace != (size_t) -1)
- key[last_key_whitespace] = 0;
-
- r = push(fname, line, key, value, userdata, n_pushed);
- if (r < 0)
- return r;
-
- n_key = 0;
- value = NULL;
- value_alloc = n_value = 0;
-
- } else if (c == '\'')
- state = SINGLE_QUOTE_VALUE;
- else if (c == '\"')
- state = DOUBLE_QUOTE_VALUE;
- else if (c == '\\')
- state = VALUE_ESCAPE;
- else if (!strchr(WHITESPACE, c)) {
- state = VALUE;
-
- if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
- return -ENOMEM;
-
- value[n_value++] = c;
- }
-
- break;
-
- case VALUE:
- if (strchr(NEWLINE, c)) {
- state = PRE_KEY;
- line++;
-
- key[n_key] = 0;
-
- if (value)
- value[n_value] = 0;
-
- /* Chomp off trailing whitespace from value */
- if (last_value_whitespace != (size_t) -1)
- value[last_value_whitespace] = 0;
-
- /* strip trailing whitespace from key */
- if (last_key_whitespace != (size_t) -1)
- key[last_key_whitespace] = 0;
-
- r = push(fname, line, key, value, userdata, n_pushed);
- if (r < 0)
- return r;
-
- n_key = 0;
- value = NULL;
- value_alloc = n_value = 0;
-
- } else if (c == '\\') {
- state = VALUE_ESCAPE;
- last_value_whitespace = (size_t) -1;
- } else {
- if (!strchr(WHITESPACE, c))
- last_value_whitespace = (size_t) -1;
- else if (last_value_whitespace == (size_t) -1)
- last_value_whitespace = n_value;
-
- if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
- return -ENOMEM;
-
- value[n_value++] = c;
- }
-
- break;
-
- case VALUE_ESCAPE:
- state = VALUE;
-
- if (!strchr(NEWLINE, c)) {
- /* Escaped newlines we eat up entirely */
- if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
- return -ENOMEM;
-
- value[n_value++] = c;
- }
- break;
-
- case SINGLE_QUOTE_VALUE:
- if (c == '\'')
- state = PRE_VALUE;
- else if (c == '\\')
- state = SINGLE_QUOTE_VALUE_ESCAPE;
- else {
- if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
- return -ENOMEM;
-
- value[n_value++] = c;
- }
-
- break;
-
- case SINGLE_QUOTE_VALUE_ESCAPE:
- state = SINGLE_QUOTE_VALUE;
-
- if (!strchr(NEWLINE, c)) {
- if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
- return -ENOMEM;
-
- value[n_value++] = c;
- }
- break;
-
- case DOUBLE_QUOTE_VALUE:
- if (c == '\"')
- state = PRE_VALUE;
- else if (c == '\\')
- state = DOUBLE_QUOTE_VALUE_ESCAPE;
- else {
- if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
- return -ENOMEM;
-
- value[n_value++] = c;
- }
-
- break;
-
- case DOUBLE_QUOTE_VALUE_ESCAPE:
- state = DOUBLE_QUOTE_VALUE;
-
- if (!strchr(NEWLINE, c)) {
- if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
- return -ENOMEM;
-
- value[n_value++] = c;
- }
- break;
-
- case COMMENT:
- if (c == '\\')
- state = COMMENT_ESCAPE;
- else if (strchr(NEWLINE, c)) {
- state = PRE_KEY;
- line++;
- }
- break;
-
- case COMMENT_ESCAPE:
- state = COMMENT;
- break;
- }
- }
-
- if (IN_SET(state,
- PRE_VALUE,
- VALUE,
- VALUE_ESCAPE,
- SINGLE_QUOTE_VALUE,
- SINGLE_QUOTE_VALUE_ESCAPE,
- DOUBLE_QUOTE_VALUE,
- DOUBLE_QUOTE_VALUE_ESCAPE)) {
-
- key[n_key] = 0;
-
- if (value)
- value[n_value] = 0;
-
- if (state == VALUE)
- if (last_value_whitespace != (size_t) -1)
- value[last_value_whitespace] = 0;
-
- /* strip trailing whitespace from key */
- if (last_key_whitespace != (size_t) -1)
- key[last_key_whitespace] = 0;
-
- r = push(fname, line, key, value, userdata, n_pushed);
- if (r < 0)
- return r;
-
- value = NULL;
- }
-
- return 0;
-}
-
-static int check_utf8ness_and_warn(
- const char *filename, unsigned line,
- const char *key, char *value) {
-
- if (!utf8_is_valid(key)) {
- _cleanup_free_ char *p = NULL;
-
- p = utf8_escape_invalid(key);
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s:%u: invalid UTF-8 in key '%s', ignoring.",
- strna(filename), line, p);
- }
-
- if (value && !utf8_is_valid(value)) {
- _cleanup_free_ char *p = NULL;
-
- p = utf8_escape_invalid(value);
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
- strna(filename), line, key, p);
- }
-
- return 0;
-}
-
-static int parse_env_file_push(
- const char *filename, unsigned line,
- const char *key, char *value,
- void *userdata,
- int *n_pushed) {
-
- const char *k;
- va_list aq, *ap = userdata;
- int r;
-
- r = check_utf8ness_and_warn(filename, line, key, value);
- if (r < 0)
- return r;
-
- va_copy(aq, *ap);
-
- while ((k = va_arg(aq, const char *))) {
- char **v;
-
- v = va_arg(aq, char **);
-
- if (streq(key, k)) {
- va_end(aq);
- free(*v);
- *v = value;
-
- if (n_pushed)
- (*n_pushed)++;
-
- return 1;
- }
- }
-
- va_end(aq);
- free(value);
-
- return 0;
-}
-
-int parse_env_filev(
- FILE *f,
- const char *fname,
- va_list ap) {
-
- int r, n_pushed = 0;
- va_list aq;
-
- va_copy(aq, ap);
- r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed);
- va_end(aq);
- if (r < 0)
- return r;
-
- return n_pushed;
-}
-
-int parse_env_file_sentinel(
- FILE *f,
- const char *fname,
- ...) {
-
- va_list ap;
- int r;
-
- va_start(ap, fname);
- r = parse_env_filev(f, fname, ap);
- va_end(ap);
-
- return r;
-}
-
#if 0 /* NM_IGNORED */
-static int load_env_file_push(
- const char *filename, unsigned line,
- const char *key, char *value,
- void *userdata,
- int *n_pushed) {
- char ***m = userdata;
- char *p;
- int r;
-
- r = check_utf8ness_and_warn(filename, line, key, value);
- if (r < 0)
- return r;
-
- p = strjoin(key, "=", value);
- if (!p)
- return -ENOMEM;
-
- r = strv_env_replace(m, p);
- if (r < 0) {
- free(p);
- return r;
- }
-
- if (n_pushed)
- (*n_pushed)++;
-
- free(value);
- return 0;
-}
-
-int load_env_file(FILE *f, const char *fname, char ***rl) {
- char **m = NULL;
- int r;
-
- r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
- if (r < 0) {
- strv_free(m);
- return r;
- }
-
- *rl = m;
- return 0;
-}
-
-static int load_env_file_push_pairs(
- const char *filename, unsigned line,
- const char *key, char *value,
- void *userdata,
- int *n_pushed) {
- char ***m = userdata;
- int r;
-
- r = check_utf8ness_and_warn(filename, line, key, value);
- if (r < 0)
- return r;
-
- r = strv_extend(m, key);
- if (r < 0)
- return -ENOMEM;
-
- if (!value) {
- r = strv_extend(m, "");
- if (r < 0)
- return -ENOMEM;
- } else {
- r = strv_push(m, value);
- if (r < 0)
- return r;
- }
-
- if (n_pushed)
- (*n_pushed)++;
-
- return 0;
-}
-
-int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
- char **m = NULL;
- int r;
-
- r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
- if (r < 0) {
- strv_free(m);
- return r;
- }
-
- *rl = m;
- return 0;
-}
-
-static int merge_env_file_push(
- const char *filename, unsigned line,
- const char *key, char *value,
- void *userdata,
- int *n_pushed) {
-
- char ***env = userdata;
- char *expanded_value;
-
- assert(env);
-
- if (!value) {
- log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
- return 0;
- }
-
- if (!env_name_is_valid(key)) {
- log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key);
- free(value);
- return 0;
- }
-
- expanded_value = replace_env(value, *env,
- REPLACE_ENV_USE_ENVIRONMENT|
- REPLACE_ENV_ALLOW_BRACELESS|
- REPLACE_ENV_ALLOW_EXTENDED);
- if (!expanded_value)
- return -ENOMEM;
-
- free_and_replace(value, expanded_value);
-
- return load_env_file_push(filename, line, key, value, env, n_pushed);
-}
-
-int merge_env_file(
- char ***env,
- FILE *f,
- const char *fname) {
-
- /* NOTE: this function supports braceful and braceless variable expansions,
- * plus "extended" substitutions, unlike other exported parsing functions.
- */
-
- return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL);
-}
-
-static void write_env_var(FILE *f, const char *v) {
- const char *p;
-
- p = strchr(v, '=');
- if (!p) {
- /* Fallback */
- fputs_unlocked(v, f);
- fputc_unlocked('\n', f);
- return;
- }
-
- p++;
- fwrite_unlocked(v, 1, p-v, f);
-
- if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
- fputc_unlocked('\"', f);
-
- for (; *p; p++) {
- if (strchr(SHELL_NEED_ESCAPE, *p))
- fputc_unlocked('\\', f);
-
- fputc_unlocked(*p, f);
- }
-
- fputc_unlocked('\"', f);
- } else
- fputs_unlocked(p, f);
-
- fputc_unlocked('\n', f);
-}
-
-int write_env_file(const char *fname, char **l) {
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *p = NULL;
- char **i;
- int r;
-
- assert(fname);
-
- r = fopen_temporary(fname, &f, &p);
- if (r < 0)
- return r;
-
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
- (void) fchmod_umask(fileno(f), 0644);
-
- STRV_FOREACH(i, l)
- write_env_var(f, *i);
-
- r = fflush_and_check(f);
- if (r >= 0) {
- if (rename(p, fname) >= 0)
- return 0;
-
- r = -errno;
- }
-
- unlink(p);
- return r;
-}
-
int executable_is_script(const char *path, char **interpreter) {
_cleanup_free_ char *line = NULL;
size_t len;
@@ -1136,39 +581,6 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
}
#endif /* NM_IGNORED */
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
- FILE *f;
- char *t;
- int r, fd;
-
- assert(path);
- assert(_f);
- assert(_temp_path);
-
- r = tempfn_xxxxxx(path, NULL, &t);
- if (r < 0)
- return r;
-
- fd = mkostemp_safe(t);
- if (fd < 0) {
- free(t);
- return -errno;
- }
-
- f = fdopen(fd, "we");
- if (!f) {
- unlink_noerrno(t);
- free(t);
- safe_close(fd);
- return -errno;
- }
-
- *_f = f;
- *_temp_path = t;
-
- return 0;
-}
-
int fflush_and_check(FILE *f) {
assert(f);
@@ -1200,165 +612,6 @@ int fflush_sync_and_check(FILE *f) {
return 0;
}
-#endif /* NM_IGNORED */
-
-/* This is much like mkostemp() but is subject to umask(). */
-int mkostemp_safe(char *pattern) {
- _cleanup_umask_ mode_t u = 0;
- int fd;
-
- assert(pattern);
-
- u = umask(077);
-
- fd = mkostemp(pattern, O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- return fd;
-}
-
-int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
- int fd;
- FILE *f;
-
- fd = mkostemp_safe(pattern);
- if (fd < 0)
- return fd;
-
- f = fdopen(fd, mode);
- if (!f) {
- safe_close(fd);
- return -errno;
- }
-
- *ret_f = f;
- return 0;
-}
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
- const char *fn;
- char *t;
-
- assert(ret);
-
- if (isempty(p))
- return -EINVAL;
- if (path_equal(p, "/"))
- return -EINVAL;
-
- /*
- * Turns this:
- * /foo/bar/waldo
- *
- * Into this:
- * /foo/bar/.#<extra>waldoXXXXXX
- */
-
- fn = basename(p);
- if (!filename_is_valid(fn))
- return -EINVAL;
-
- extra = strempty(extra);
-
- t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
- if (!t)
- return -ENOMEM;
-
- strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
-
- *ret = path_simplify(t, false);
- return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int tempfn_random(const char *p, const char *extra, char **ret) {
- const char *fn;
- char *t, *x;
- uint64_t u;
- unsigned i;
-
- assert(ret);
-
- if (isempty(p))
- return -EINVAL;
- if (path_equal(p, "/"))
- return -EINVAL;
-
- /*
- * Turns this:
- * /foo/bar/waldo
- *
- * Into this:
- * /foo/bar/.#<extra>waldobaa2a261115984a9
- */
-
- fn = basename(p);
- if (!filename_is_valid(fn))
- return -EINVAL;
-
- extra = strempty(extra);
-
- t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
- if (!t)
- return -ENOMEM;
-
- x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
-
- u = random_u64();
- for (i = 0; i < 16; i++) {
- *(x++) = hexchar(u & 0xF);
- u >>= 4;
- }
-
- *x = 0;
-
- *ret = path_simplify(t, false);
- return 0;
-}
-
-int tempfn_random_child(const char *p, const char *extra, char **ret) {
- char *t, *x;
- uint64_t u;
- unsigned i;
- int r;
-
- assert(ret);
-
- /* Turns this:
- * /foo/bar/waldo
- * Into this:
- * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
- */
-
- if (!p) {
- r = tmp_dir(&p);
- if (r < 0)
- return r;
- }
-
- extra = strempty(extra);
-
- t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
- if (!t)
- return -ENOMEM;
-
- if (isempty(p))
- x = stpcpy(stpcpy(t, ".#"), extra);
- else
- x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
-
- u = random_u64();
- for (i = 0; i < 16; i++) {
- *(x++) = hexchar(u & 0xF);
- u >>= 4;
- }
-
- *x = 0;
-
- *ret = path_simplify(t, false);
- return 0;
-}
int write_timestamp_file_atomic(const char *fn, usec_t n) {
char ln[DECIMAL_STR_MAX(n)+2];
@@ -1425,198 +678,53 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
}
#if 0 /* NM_IGNORED */
-int open_tmpfile_unlinkable(const char *directory, int flags) {
- char *p;
- int fd, r;
-
- if (!directory) {
- r = tmp_dir(&directory);
- if (r < 0)
- return r;
- } else if (isempty(directory))
- return -EINVAL;
-
- /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
-
- /* Try O_TMPFILE first, if it is supported */
- fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
- if (fd >= 0)
- return fd;
-
- /* Fall back to unguessable name + unlinking */
- p = strjoina(directory, "/systemd-tmp-XXXXXX");
-
- fd = mkostemp_safe(p);
- if (fd < 0)
- return fd;
-
- (void) unlink(p);
-
- return fd;
-}
-
-int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
- _cleanup_free_ char *tmp = NULL;
- int r, fd;
-
- assert(target);
- assert(ret_path);
-
- /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
- assert((flags & O_EXCL) == 0);
-
- /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
- * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
- * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
-
- fd = open_parent(target, O_TMPFILE|flags, 0640);
- if (fd >= 0) {
- *ret_path = NULL;
- return fd;
- }
-
- log_debug_errno(fd, "Failed to use O_TMPFILE for %s: %m", target);
-
- r = tempfn_random(target, NULL, &tmp);
- if (r < 0)
- return r;
-
- fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
- if (fd < 0)
- return -errno;
-
- *ret_path = TAKE_PTR(tmp);
-
- return fd;
-}
-
-int open_serialization_fd(const char *ident) {
- int fd = -1;
-
- fd = memfd_create(ident, MFD_CLOEXEC);
- if (fd < 0) {
- const char *path;
-
- path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
- fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- log_debug("Serializing %s to %s.", ident, path);
- } else
- log_debug("Serializing %s to memfd.", ident);
-
- return fd;
-}
-
-int link_tmpfile(int fd, const char *path, const char *target) {
- int r;
-
- assert(fd >= 0);
- assert(target);
-
- /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
- * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
- * on the directory, and renameat2() is used instead.
- *
- * Note that in both cases we will not replace existing files. This is because linkat() does not support this
- * operation currently (renameat2() does), and there is no nice way to emulate this. */
-
- if (path) {
- r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
- if (r < 0)
- return r;
- } else {
- char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
-
- xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
-
- if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
- return -errno;
- }
-
- return 0;
-}
-
-int read_nul_string(FILE *f, char **ret) {
- _cleanup_free_ char *x = NULL;
- size_t allocated = 0, n = 0;
-
- assert(f);
- assert(ret);
-
- /* Reads a NUL-terminated string from the specified file. */
-
- for (;;) {
- int c;
-
- if (!GREEDY_REALLOC(x, allocated, n+2))
- return -ENOMEM;
-
- c = fgetc(f);
- if (c == 0) /* Terminate at NUL byte */
- break;
- if (c == EOF) {
- if (ferror(f))
- return -errno;
- break; /* Terminate at EOF */
- }
+/* A bitmask of the EOL markers we know */
+typedef enum EndOfLineMarker {
+ EOL_NONE = 0,
+ EOL_ZERO = 1 << 0, /* \0 (aka NUL) */
+ EOL_TEN = 1 << 1, /* \n (aka NL, aka LF) */
+ EOL_THIRTEEN = 1 << 2, /* \r (aka CR) */
+} EndOfLineMarker;
- x[n++] = (char) c;
- }
+static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
- if (x)
- x[n] = 0;
- else {
- x = new0(char, 1);
- if (!x)
- return -ENOMEM;
+ if (!IN_SET(flags, READ_LINE_ONLY_NUL)) {
+ if (c == '\n')
+ return EOL_TEN;
+ if (c == '\r')
+ return EOL_THIRTEEN;
}
- *ret = TAKE_PTR(x);
-
- return 0;
-}
+ if (c == '\0')
+ return EOL_ZERO;
-int mkdtemp_malloc(const char *template, char **ret) {
- _cleanup_free_ char *p = NULL;
- int r;
-
- assert(ret);
-
- if (template)
- p = strdup(template);
- else {
- const char *tmp;
-
- r = tmp_dir(&tmp);
- if (r < 0)
- return r;
-
- p = strjoin(tmp, "/XXXXXX");
- }
- if (!p)
- return -ENOMEM;
-
- if (!mkdtemp(p))
- return -errno;
-
- *ret = TAKE_PTR(p);
- return 0;
+ return EOL_NONE;
}
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
-int read_line(FILE *f, size_t limit, char **ret) {
- _cleanup_free_ char *buffer = NULL;
+int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
size_t n = 0, allocated = 0, count = 0;
+ _cleanup_free_ char *buffer = NULL;
+ int r;
assert(f);
/* Something like a bounded version of getline().
*
- * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
- * returned.
+ * Considers EOF, \n, \r and \0 end of line delimiters (or combinations of these), and does not include these
+ * delimiters in the string returned. Specifically, recognizes the following combinations of markers as line
+ * endings:
+ *
+ * • \n (UNIX)
+ * • \r (old MacOS)
+ * • \0 (C strings)
+ * • \n\0
+ * • \r\0
+ * • \r\n (Windows)
+ * • \n\r
+ * • \r\n\0
+ * • \n\r\0
*
* Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
* the number of characters in the returned string). When EOF is hit, 0 is returned.
@@ -1633,34 +741,55 @@ int read_line(FILE *f, size_t limit, char **ret) {
{
_unused_ _cleanup_(funlockfilep) FILE *flocked = f;
+ EndOfLineMarker previous_eol = EOL_NONE;
flockfile(f);
for (;;) {
- int c;
+ EndOfLineMarker eol;
+ char c;
if (n >= limit)
return -ENOBUFS;
- errno = 0;
- c = fgetc_unlocked(f);
- if (c == EOF) {
- /* if we read an error, and have no data to return, then propagate the error */
- if (ferror_unlocked(f) && n == 0)
- return errno > 0 ? -errno : -EIO;
+ if (count >= INT_MAX) /* We couldn't return the counter anymore as "int", hence refuse this */
+ return -ENOBUFS;
+
+ r = safe_fgetc(f, &c);
+ if (r < 0)
+ return r;
+ if (r == 0) /* EOF is definitely EOL */
+ break;
+ eol = categorize_eol(c, flags);
+
+ if (FLAGS_SET(previous_eol, EOL_ZERO) ||
+ (eol == EOL_NONE && previous_eol != EOL_NONE) ||
+ (eol != EOL_NONE && (previous_eol & eol) != 0)) {
+ /* Previous char was a NUL? This is not an EOL, but the previous char was? This type of
+ * EOL marker has been seen right before? In either of these three cases we are
+ * done. But first, let's put this character back in the queue. (Note that we have to
+ * cast this to (unsigned char) here as ungetc() expects a positive 'int', and if we
+ * are on an architecture where 'char' equals 'signed char' we need to ensure we don't
+ * pass a negative value here. That said, to complicate things further ungetc() is
+ * actually happy with most negative characters and implicitly casts them back to
+ * positive ones as needed, except for \xff (aka -1, aka EOF), which it refuses. What a
+ * godawful API!) */
+ assert_se(ungetc((unsigned char) c, f) != EOF);
break;
}
count++;
- if (IN_SET(c, '\n', 0)) /* Reached a delimiter */
- break;
+ if (eol != EOL_NONE) {
+ previous_eol |= eol;
+ continue;
+ }
if (ret) {
if (!GREEDY_REALLOC(buffer, allocated, n + 2))
return -ENOMEM;
- buffer[n] = (char) c;
+ buffer[n] = c;
}
n++;
@@ -1675,4 +804,31 @@ int read_line(FILE *f, size_t limit, char **ret) {
return (int) count;
}
+
+int safe_fgetc(FILE *f, char *ret) {
+ int k;
+
+ assert(f);
+
+ /* A safer version of plain fgetc(): let's propagate the error that happened while reading as such, and
+ * separate the EOF condition from the byte read, to avoid those confusion signed/unsigned issues fgetc()
+ * has. */
+
+ errno = 0;
+ k = fgetc(f);
+ if (k == EOF) {
+ if (ferror(f))
+ return errno > 0 ? -errno : -EIO;
+
+ if (ret)
+ *ret = 0;
+
+ return 0;
+ }
+
+ if (ret)
+ *ret = k;
+
+ return 1;
+}
#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/fileio.h b/src/systemd/src/basic/fileio.h
index dae115e3bb..53e3f4ef5f 100644
--- a/src/systemd/src/basic/fileio.h
+++ b/src/systemd/src/basic/fileio.h
@@ -44,16 +44,6 @@ int read_full_stream(FILE *f, char **contents, size_t *size);
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
-int parse_env_filev(FILE *f, const char *fname, va_list ap);
-int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
-#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
-int load_env_file(FILE *f, const char *fname, char ***l);
-int load_env_file_pairs(FILE *f, const char *fname, char ***l);
-
-int merge_env_file(char ***env, FILE *f, const char *fname);
-
-int write_env_file(const char *fname, char **l);
-
int executable_is_script(const char *path, char **interpreter);
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
@@ -66,27 +56,23 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
int fflush_and_check(FILE *f);
int fflush_sync_and_check(FILE *f);
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
-int mkostemp_safe(char *pattern);
-int fmkostemp_safe(char *pattern, const char *mode, FILE**_f);
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
-int tempfn_random(const char *p, const char *extra, char **ret);
-int tempfn_random_child(const char *p, const char *extra, char **ret);
-
int write_timestamp_file_atomic(const char *fn, usec_t n);
int read_timestamp_file(const char *fn, usec_t *ret);
int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
-int open_tmpfile_unlinkable(const char *directory, int flags);
-int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
-int open_serialization_fd(const char *ident);
+typedef enum ReadLineFlags {
+ READ_LINE_ONLY_NUL = 1 << 0,
+} ReadLineFlags;
-int link_tmpfile(int fd, const char *path, const char *target);
+int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret);
-int read_nul_string(FILE *f, char **ret);
+static inline int read_line(FILE *f, size_t limit, char **ret) {
+ return read_line_full(f, limit, 0, ret);
+}
-int mkdtemp_malloc(const char *template, char **ret);
+static inline int read_nul_string(FILE *f, size_t limit, char **ret) {
+ return read_line_full(f, limit, READ_LINE_ONLY_NUL, ret);
+}
-int read_line(FILE *f, size_t limit, char **ret);
+int safe_fgetc(FILE *f, char *ret);
diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c
index 5966c3835b..767e5e078f 100644
--- a/src/systemd/src/basic/fs-util.c
+++ b/src/systemd/src/basic/fs-util.c
@@ -15,8 +15,8 @@
#include "alloc-util.h"
#include "dirent-util.h"
#include "fd-util.h"
-#include "fileio.h"
#include "fs-util.h"
+#include "locale-util.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
@@ -29,6 +29,7 @@
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
+#include "tmpfile-util.h"
#include "user-util.h"
#include "util.h"
@@ -216,31 +217,62 @@ int readlink_and_make_absolute(const char *p, char **r) {
}
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
+ char fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
+ _cleanup_close_ int fd = -1;
assert(path);
- /* Under the assumption that we are running privileged we
- * first change the access mode and only then hand out
+ /* Under the assumption that we are running privileged we first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
- if (mode != MODE_INVALID)
- if (chmod(path, mode) < 0)
+ fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change mode/owner
+ * on the same file */
+ if (fd < 0)
+ return -errno;
+
+ xsprintf(fd_path, "/proc/self/fd/%i", fd);
+
+ if (mode != MODE_INVALID) {
+
+ if ((mode & S_IFMT) != 0) {
+ struct stat st;
+
+ if (stat(fd_path, &st) < 0)
+ return -errno;
+
+ if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
+ return -EINVAL;
+ }
+
+ if (chmod(fd_path, mode & 07777) < 0)
return -errno;
+ }
if (uid != UID_INVALID || gid != GID_INVALID)
- if (chown(path, uid, gid) < 0)
+ if (chown(fd_path, uid, gid) < 0)
return -errno;
return 0;
}
int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
- /* Under the assumption that we are running privileged we
- * first change the access mode and only then hand out
+ /* Under the assumption that we are running privileged we first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
- if (mode != MODE_INVALID)
- if (fchmod(fd, mode) < 0)
+ if (mode != MODE_INVALID) {
+
+ if ((mode & S_IFMT) != 0) {
+ struct stat st;
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
+ return -EINVAL;
+ }
+
+ if (fchmod(fd, mode & 0777) < 0)
return -errno;
+ }
if (uid != UID_INVALID || gid != GID_INVALID)
if (fchown(fd, uid, gid) < 0)
@@ -270,7 +302,6 @@ int fchmod_opath(int fd, mode_t m) {
* fchownat() does. */
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
-
if (chmod(procfs_path, m) < 0)
return -errno;
@@ -642,15 +673,42 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
}
#if 0 /* NM_IGNORED */
-static bool safe_transition(const struct stat *a, const struct stat *b) {
+static bool unsafe_transition(const struct stat *a, const struct stat *b) {
/* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
* privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
* making us believe we read something safe even though it isn't safe in the specific context we open it in. */
if (a->st_uid == 0) /* Transitioning from privileged to unprivileged is always fine */
- return true;
+ return false;
+
+ return a->st_uid != b->st_uid; /* Otherwise we need to stay within the same UID */
+}
+
+static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) {
+ _cleanup_free_ char *n1 = NULL, *n2 = NULL;
- return a->st_uid == b->st_uid; /* Otherwise we need to stay within the same UID */
+ if (!FLAGS_SET(flags, CHASE_WARN))
+ return -ENOLINK;
+
+ (void) fd_get_path(a, &n1);
+ (void) fd_get_path(b, &n2);
+
+ return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
+ "Detected unsafe path transition %s %s %s during canonicalization of %s.",
+ n1, special_glyph(SPECIAL_GLYPH_ARROW), n2, path);
+}
+
+static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
+ _cleanup_free_ char *n1 = NULL;
+
+ if (!FLAGS_SET(flags, CHASE_WARN))
+ return -EREMOTE;
+
+ (void) fd_get_path(fd, &n1);
+
+ return log_warning_errno(SYNTHETIC_ERRNO(EREMOTE),
+ "Detected autofs mount point %s during canonicalization of %s.",
+ n1, path);
}
int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) {
@@ -713,6 +771,14 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
* path is fully normalized, and == 0 for each normalization step. This may be combined with
* CHASE_NONEXISTENT, in which case 1 is returned when a component is not found.
*
+ * 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
+ * unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
+ * CHASE_WARN is also set a warning describing the unsafe transition is emitted.
+ *
+ * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, the path normalization is
+ * aborted and -EREMOTE is returned. If CHASE_WARN is also set a warning showing the path of the mount point
+ * is emitted.
+ *
* */
/* A root directory of "/" or "" is identical to none */
@@ -827,8 +893,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(fd_parent, &st) < 0)
return -errno;
- if (!safe_transition(&previous_stat, &st))
- return -EPERM;
+ if (unsafe_transition(&previous_stat, &st))
+ return log_unsafe_transition(fd, fd_parent, path, flags);
previous_stat = st;
}
@@ -868,14 +934,14 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(child, &st) < 0)
return -errno;
if ((flags & CHASE_SAFE) &&
- !safe_transition(&previous_stat, &st))
- return -EPERM;
+ unsafe_transition(&previous_stat, &st))
+ return log_unsafe_transition(fd, child, path, flags);
previous_stat = st;
if ((flags & CHASE_NO_AUTOFS) &&
fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
- return -EREMOTE;
+ return log_autofs_mount_point(child, path, flags);
if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
char *joined;
@@ -907,8 +973,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(fd, &st) < 0)
return -errno;
- if (!safe_transition(&previous_stat, &st))
- return -EPERM;
+ if (unsafe_transition(&previous_stat, &st))
+ return log_unsafe_transition(child, fd, path, flags);
previous_stat = st;
}
diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h
index 955b146a6a..7ad030be5d 100644
--- a/src/systemd/src/basic/fs-util.h
+++ b/src/systemd/src/basic/fs-util.h
@@ -74,6 +74,7 @@ enum {
CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */
CHASE_STEP = 1 << 6, /* If set, just execute a single step of the normalization */
CHASE_NOFOLLOW = 1 << 7, /* Only valid with CHASE_OPEN: when the path's right-most component refers to symlink return O_PATH fd of the symlink, rather than following it. */
+ CHASE_WARN = 1 << 8, /* Emit an appropriate warning when an error is encountered */
};
/* How many iterations to execute before returning -ELOOP */
diff --git a/src/systemd/src/basic/hash-funcs.c b/src/systemd/src/basic/hash-funcs.c
index fc2c4f7824..33264859ed 100644
--- a/src/systemd/src/basic/hash-funcs.c
+++ b/src/systemd/src/basic/hash-funcs.c
@@ -7,22 +7,14 @@
#include "hash-funcs.h"
#include "path-util.h"
-void string_hash_func(const void *p, struct siphash *state) {
+void string_hash_func(const char *p, struct siphash *state) {
siphash24_compress(p, strlen(p) + 1, state);
}
#if 0 /* NM_IGNORED */
-int string_compare_func(const void *a, const void *b) {
- return strcmp(a, b);
-}
-
-const struct hash_ops string_hash_ops = {
- .hash = string_hash_func,
- .compare = string_compare_func
-};
+DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func);
-void path_hash_func(const void *p, struct siphash *state) {
- const char *q = p;
+void path_hash_func(const char *q, struct siphash *state) {
size_t n;
assert(q);
@@ -60,14 +52,11 @@ void path_hash_func(const void *p, struct siphash *state) {
}
}
-int path_compare_func(const void *a, const void *b) {
+int path_compare_func(const char *a, const char *b) {
return path_compare(a, b);
}
-const struct hash_ops path_hash_ops = {
- .hash = path_hash_func,
- .compare = path_compare_func
-};
+DEFINE_HASH_OPS(path_hash_ops, char, path_hash_func, path_compare_func);
#endif /* NM_IGNORED */
void trivial_hash_func(const void *p, struct siphash *state) {
@@ -80,41 +69,29 @@ int trivial_compare_func(const void *a, const void *b) {
const struct hash_ops trivial_hash_ops = {
.hash = trivial_hash_func,
- .compare = trivial_compare_func
+ .compare = trivial_compare_func,
};
-void uint64_hash_func(const void *p, struct siphash *state) {
+void uint64_hash_func(const uint64_t *p, struct siphash *state) {
siphash24_compress(p, sizeof(uint64_t), state);
}
-int uint64_compare_func(const void *_a, const void *_b) {
- uint64_t a, b;
- a = *(const uint64_t*) _a;
- b = *(const uint64_t*) _b;
- return CMP(a, b);
+int uint64_compare_func(const uint64_t *a, const uint64_t *b) {
+ return CMP(*a, *b);
}
-const struct hash_ops uint64_hash_ops = {
- .hash = uint64_hash_func,
- .compare = uint64_compare_func
-};
+DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func);
#if 0 /* NM_IGNORED */
#if SIZEOF_DEV_T != 8
-void devt_hash_func(const void *p, struct siphash *state) {
+void devt_hash_func(const dev_t *p, struct siphash *state) {
siphash24_compress(p, sizeof(dev_t), state);
}
-int devt_compare_func(const void *_a, const void *_b) {
- dev_t a, b;
- a = *(const dev_t*) _a;
- b = *(const dev_t*) _b;
- return CMP(a, b);
+int devt_compare_func(const dev_t *a, const dev_t *b) {
+ return CMP(*a, *b);
}
-const struct hash_ops devt_hash_ops = {
- .hash = devt_hash_func,
- .compare = devt_compare_func
-};
+DEFINE_HASH_OPS(devt_hash_ops, dev_t, devt_hash_func, devt_compare_func);
#endif
#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/hash-funcs.h b/src/systemd/src/basic/hash-funcs.h
index fa45cfe256..3d2ae4b55e 100644
--- a/src/systemd/src/basic/hash-funcs.h
+++ b/src/systemd/src/basic/hash-funcs.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "alloc-util.h"
#include "macro.h"
#include "siphash24.h"
@@ -10,14 +11,74 @@ typedef int (*compare_func_t)(const void *a, const void *b);
struct hash_ops {
hash_func_t hash;
compare_func_t compare;
+ free_func_t free_key;
+ free_func_t free_value;
};
-void string_hash_func(const void *p, struct siphash *state);
-int string_compare_func(const void *a, const void *b) _pure_;
+#define _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func, free_key_func, free_value_func, scope) \
+ _unused_ static void (* UNIQ_T(static_hash_wrapper, uq))(const type *, struct siphash *) = hash_func; \
+ _unused_ static int (* UNIQ_T(static_compare_wrapper, uq))(const type *, const type *) = compare_func; \
+ scope const struct hash_ops name = { \
+ .hash = (hash_func_t) hash_func, \
+ .compare = (compare_func_t) compare_func, \
+ .free_key = free_key_func, \
+ .free_value = free_value_func, \
+ }
+
+#define _DEFINE_FREE_FUNC(uq, type, wrapper_name, func) \
+ /* Type-safe free function */ \
+ static void UNIQ_T(wrapper_name, uq)(void *a) { \
+ type *_a = a; \
+ func(_a); \
+ }
+
+#define _DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(uq, name, type, hash_func, compare_func, free_func, scope) \
+ _DEFINE_FREE_FUNC(uq, type, static_free_wrapper, free_func); \
+ _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func, \
+ UNIQ_T(static_free_wrapper, uq), NULL, scope)
+
+#define _DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(uq, name, type, hash_func, compare_func, type_value, free_func, scope) \
+ _DEFINE_FREE_FUNC(uq, type_value, static_free_wrapper, free_func); \
+ _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func, \
+ NULL, UNIQ_T(static_free_wrapper, uq), scope)
+
+#define _DEFINE_HASH_OPS_FULL(uq, name, type, hash_func, compare_func, free_key_func, type_value, free_value_func, scope) \
+ _DEFINE_FREE_FUNC(uq, type, static_free_key_wrapper, free_key_func); \
+ _DEFINE_FREE_FUNC(uq, type_value, static_free_value_wrapper, free_value_func); \
+ _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func, \
+ UNIQ_T(static_free_key_wrapper, uq), \
+ UNIQ_T(static_free_value_wrapper, uq), scope)
+
+#define DEFINE_HASH_OPS(name, type, hash_func, compare_func) \
+ _DEFINE_HASH_OPS(UNIQ, name, type, hash_func, compare_func, NULL, NULL,)
+
+#define DEFINE_PRIVATE_HASH_OPS(name, type, hash_func, compare_func) \
+ _DEFINE_HASH_OPS(UNIQ, name, type, hash_func, compare_func, NULL, NULL, static)
+
+#define DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(name, type, hash_func, compare_func, free_func) \
+ _DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, free_func,)
+
+#define DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(name, type, hash_func, compare_func, free_func) \
+ _DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, free_func, static)
+
+#define DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(name, type, hash_func, compare_func, value_type, free_func) \
+ _DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, value_type, free_func,)
+
+#define DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(name, type, hash_func, compare_func, value_type, free_func) \
+ _DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, value_type, free_func, static)
+
+#define DEFINE_HASH_OPS_FULL(name, type, hash_func, compare_func, free_key_func, value_type, free_value_func) \
+ _DEFINE_HASH_OPS_FULL(UNIQ, name, type, hash_func, compare_func, free_key_func, value_type, free_value_func,)
+
+#define DEFINE_PRIVATE_HASH_OPS_FULL(name, type, hash_func, compare_func, free_key_func, value_type, free_value_func) \
+ _DEFINE_HASH_OPS_FULL(UNIQ, name, type, hash_func, compare_func, free_key_func, value_type, free_value_func, static)
+
+void string_hash_func(const char *p, struct siphash *state);
+#define string_compare_func strcmp
extern const struct hash_ops string_hash_ops;
-void path_hash_func(const void *p, struct siphash *state);
-int path_compare_func(const void *a, const void *b) _pure_;
+void path_hash_func(const char *p, struct siphash *state);
+int path_compare_func(const char *a, const char *b) _pure_;
extern const struct hash_ops path_hash_ops;
/* This will compare the passed pointers directly, and will not dereference them. This is hence not useful for strings
@@ -28,15 +89,15 @@ extern const struct hash_ops trivial_hash_ops;
/* 32bit values we can always just embed in the pointer itself, but in order to support 32bit archs we need store 64bit
* values indirectly, since they don't fit in a pointer. */
-void uint64_hash_func(const void *p, struct siphash *state);
-int uint64_compare_func(const void *a, const void *b) _pure_;
+void uint64_hash_func(const uint64_t *p, struct siphash *state);
+int uint64_compare_func(const uint64_t *a, const uint64_t *b) _pure_;
extern const struct hash_ops uint64_hash_ops;
/* On some archs dev_t is 32bit, and on others 64bit. And sometimes it's 64bit on 32bit archs, and sometimes 32bit on
* 64bit archs. Yuck! */
#if SIZEOF_DEV_T != 8
-void devt_hash_func(const void *p, struct siphash *state) _pure_;
-int devt_compare_func(const void *a, const void *b) _pure_;
+void devt_hash_func(const dev_t *p, struct siphash *state) _pure_;
+int devt_compare_func(const dev_t *a, const dev_t *b) _pure_;
extern const struct hash_ops devt_hash_ops;
#else
#define devt_hash_func uint64_hash_func
diff --git a/src/systemd/src/basic/hashmap.c b/src/systemd/src/basic/hashmap.c
index 328c4d3a5a..e31ffaca5e 100644
--- a/src/systemd/src/basic/hashmap.c
+++ b/src/systemd/src/basic/hashmap.c
@@ -278,7 +278,7 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
};
#if VALGRIND
-__attribute__((destructor)) static void cleanup_pools(void) {
+_destructor_ static void cleanup_pools(void) {
_cleanup_free_ char *t = NULL;
int r;
@@ -781,7 +781,7 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
h->type = type;
h->from_pool = up;
- h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops;
+ h->hash_ops = hash_ops ?: &trivial_hash_ops;
if (type == HASHMAP_TYPE_ORDERED) {
OrderedHashmap *lh = (OrderedHashmap*)h;
@@ -850,7 +850,7 @@ int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASH
static void hashmap_free_no_clear(HashmapBase *h) {
assert(!h->has_indirect);
- assert(!h->n_direct_entries);
+ assert(h->n_direct_entries == 0);
#if ENABLE_DEBUG_HASHMAP
assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
@@ -866,46 +866,41 @@ static void hashmap_free_no_clear(HashmapBase *h) {
free(h);
}
-HashmapBase *internal_hashmap_free(HashmapBase *h) {
-
- /* Free the hashmap, but nothing in it */
-
+HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
if (h) {
- internal_hashmap_clear(h);
+ internal_hashmap_clear(h, default_free_key, default_free_value);
hashmap_free_no_clear(h);
}
return NULL;
}
-HashmapBase *internal_hashmap_free_free(HashmapBase *h) {
-
- /* Free the hashmap and all data objects in it, but not the
- * keys */
+void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
+ free_func_t free_key, free_value;
+ if (!h)
+ return;
- if (h) {
- internal_hashmap_clear_free(h);
- hashmap_free_no_clear(h);
- }
+ free_key = h->hash_ops->free_key ?: default_free_key;
+ free_value = h->hash_ops->free_value ?: default_free_value;
- return NULL;
-}
+ if (free_key || free_value) {
-Hashmap *hashmap_free_free_free(Hashmap *h) {
+ /* If destructor calls are defined, let's destroy things defensively: let's take the item out of the
+ * hash table, and only then call the destructor functions. If these destructors then try to unregister
+ * themselves from our hash table a second time, the entry is already gone. */
- /* Free the hashmap and all data and key objects in it */
+ while (internal_hashmap_size(h) > 0) {
+ void *v, *k;
- if (h) {
- hashmap_clear_free_free(h);
- hashmap_free_no_clear(HASHMAP_BASE(h));
- }
+ v = internal_hashmap_first_key_and_value(h, true, &k);
- return NULL;
-}
+ if (free_key)
+ free_key(k);
-void internal_hashmap_clear(HashmapBase *h) {
- if (!h)
- return;
+ if (free_value)
+ free_value(v);
+ }
+ }
if (h->has_indirect) {
free(h->indirect.storage);
@@ -923,35 +918,6 @@ void internal_hashmap_clear(HashmapBase *h) {
base_set_dirty(h);
}
-void internal_hashmap_clear_free(HashmapBase *h) {
- unsigned idx;
-
- if (!h)
- return;
-
- for (idx = skip_free_buckets(h, 0); idx != IDX_NIL;
- idx = skip_free_buckets(h, idx + 1))
- free(entry_value(h, bucket_at(h, idx)));
-
- internal_hashmap_clear(h);
-}
-
-void hashmap_clear_free_free(Hashmap *h) {
- unsigned idx;
-
- if (!h)
- return;
-
- for (idx = skip_free_buckets(HASHMAP_BASE(h), 0); idx != IDX_NIL;
- idx = skip_free_buckets(HASHMAP_BASE(h), idx + 1)) {
- struct plain_hashmap_entry *e = plain_bucket_at(h, idx);
- free((void*)e->b.key);
- free(e->value);
- }
-
- internal_hashmap_clear(HASHMAP_BASE(h));
-}
-
static int resize_buckets(HashmapBase *h, unsigned entries_add);
/*
@@ -1515,8 +1481,8 @@ int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_
return 0;
}
-void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
- struct plain_hashmap_entry *e;
+void *internal_hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
+ struct hashmap_base_entry *e;
unsigned hash, idx;
if (!h)
@@ -1527,8 +1493,8 @@ void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
if (idx == IDX_NIL)
return NULL;
- e = plain_bucket_at(h, idx);
- if (e->value != value)
+ e = bucket_at(h, idx);
+ if (entry_value(h, e) != value)
return NULL;
remove_entry(h, idx);
@@ -1742,7 +1708,7 @@ HashmapBase *internal_hashmap_copy(HashmapBase *h) {
}
if (r < 0) {
- internal_hashmap_free(copy);
+ internal_hashmap_free(copy, false, false);
return NULL;
}
diff --git a/src/systemd/src/basic/hashmap.h b/src/systemd/src/basic/hashmap.h
index bb2a5c76ec..5bf807a76f 100644
--- a/src/systemd/src/basic/hashmap.h
+++ b/src/systemd/src/basic/hashmap.h
@@ -22,6 +22,8 @@
#define HASH_KEY_SIZE 16
+typedef void* (*hashmap_destroy_t)(void *p);
+
/* The base type for all hashmap and set types. Many functions in the
* implementation take (HashmapBase*) parameters and are run-time polymorphic,
* though the API is not meant to be polymorphic (do not call functions
@@ -87,25 +89,33 @@ OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HA
#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
-HashmapBase *internal_hashmap_free(HashmapBase *h);
+HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
static inline Hashmap *hashmap_free(Hashmap *h) {
- return (void*)internal_hashmap_free(HASHMAP_BASE(h));
+ return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
}
static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
- return (void*)internal_hashmap_free(HASHMAP_BASE(h));
+ return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, NULL);
}
-HashmapBase *internal_hashmap_free_free(HashmapBase *h);
static inline Hashmap *hashmap_free_free(Hashmap *h) {
- return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
+ return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
}
static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
- return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
+ return (void*) internal_hashmap_free(HASHMAP_BASE(h), NULL, free);
+}
+
+static inline Hashmap *hashmap_free_free_key(Hashmap *h) {
+ return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
+}
+static inline OrderedHashmap *ordered_hashmap_free_free_key(OrderedHashmap *h) {
+ return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, NULL);
}
-Hashmap *hashmap_free_free_free(Hashmap *h);
+static inline Hashmap *hashmap_free_free_free(Hashmap *h) {
+ return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
+}
static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
- return (void*)hashmap_free_free_free(PLAIN_HASHMAP(h));
+ return (void*) internal_hashmap_free(HASHMAP_BASE(h), free, free);
}
IteratedCache *iterated_cache_free(IteratedCache *cache);
@@ -181,7 +191,11 @@ static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key,
return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey);
}
-void *hashmap_remove_value(Hashmap *h, const void *key, void *value);
+void *internal_hashmap_remove_value(HashmapBase *h, const void *key, void *value);
+static inline void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
+ return internal_hashmap_remove_value(HASHMAP_BASE(h), key, value);
+}
+
static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
return hashmap_remove_value(PLAIN_HASHMAP(h), key, value);
}
@@ -258,25 +272,33 @@ static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void
return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
}
-void internal_hashmap_clear(HashmapBase *h);
+void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
static inline void hashmap_clear(Hashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h));
+ internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
}
static inline void ordered_hashmap_clear(OrderedHashmap *h) {
- internal_hashmap_clear(HASHMAP_BASE(h));
+ internal_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
}
-void internal_hashmap_clear_free(HashmapBase *h);
static inline void hashmap_clear_free(Hashmap *h) {
- internal_hashmap_clear_free(HASHMAP_BASE(h));
+ internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
}
static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
- internal_hashmap_clear_free(HASHMAP_BASE(h));
+ internal_hashmap_clear(HASHMAP_BASE(h), NULL, free);
}
-void hashmap_clear_free_free(Hashmap *h);
+static inline void hashmap_clear_free_key(Hashmap *h) {
+ internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+}
+static inline void ordered_hashmap_clear_free_key(OrderedHashmap *h) {
+ internal_hashmap_clear(HASHMAP_BASE(h), free, NULL);
+}
+
+static inline void hashmap_clear_free_free(Hashmap *h) {
+ internal_hashmap_clear(HASHMAP_BASE(h), free, free);
+}
static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
- hashmap_clear_free_free(PLAIN_HASHMAP(h));
+ internal_hashmap_clear(HASHMAP_BASE(h), free, free);
}
/*
diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c
index 0dbdfd5ce7..6a3d4afb46 100644
--- a/src/systemd/src/basic/hostname-util.c
+++ b/src/systemd/src/basic/hostname-util.c
@@ -73,12 +73,12 @@ int gethostname_strict(char **ret) {
return 0;
}
-static bool hostname_valid_char(char c) {
+bool valid_ldh_char(char c) {
return
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
- IN_SET(c, '-', '_', '.');
+ c == '-';
}
/**
@@ -94,7 +94,7 @@ static bool hostname_valid_char(char c) {
bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
unsigned n_dots = 0;
const char *p;
- bool dot;
+ bool dot, hyphen;
if (isempty(s))
return false;
@@ -104,23 +104,34 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
* sequence. Also ensures that the length stays below
* HOST_NAME_MAX. */
- for (p = s, dot = true; *p; p++) {
+ for (p = s, dot = hyphen = true; *p; p++)
if (*p == '.') {
- if (dot)
+ if (dot || hyphen)
return false;
dot = true;
+ hyphen = false;
n_dots++;
+
+ } else if (*p == '-') {
+ if (dot)
+ return false;
+
+ dot = false;
+ hyphen = true;
+
} else {
- if (!hostname_valid_char(*p))
+ if (!valid_ldh_char(*p))
return false;
dot = false;
+ hyphen = false;
}
- }
if (dot && (n_dots < 2 || !allow_trailing_dot))
return false;
+ if (hyphen)
+ return false;
if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
* Linux, but DNS allows domain names
@@ -132,29 +143,38 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
char* hostname_cleanup(char *s) {
char *p, *d;
- bool dot;
+ bool dot, hyphen;
assert(s);
- strshorten(s, HOST_NAME_MAX);
-
- for (p = s, d = s, dot = true; *p; p++) {
+ for (p = s, d = s, dot = hyphen = true; *p && d - s < HOST_NAME_MAX; p++)
if (*p == '.') {
- if (dot)
+ if (dot || hyphen)
continue;
*(d++) = '.';
dot = true;
- } else if (hostname_valid_char(*p)) {
+ hyphen = false;
+
+ } else if (*p == '-') {
+ if (dot)
+ continue;
+
+ *(d++) = '-';
+ dot = false;
+ hyphen = true;
+
+ } else if (valid_ldh_char(*p)) {
*(d++) = *p;
dot = false;
+ hyphen = false;
}
- }
- if (dot && d > s)
- d[-1] = 0;
- else
- *d = 0;
+ if (d > s && IN_SET(d[-1], '-', '.'))
+ /* The dot can occur at most once, but we might have multiple
+ * hyphens, hence the loop */
+ d--;
+ *d = 0;
return s;
}
diff --git a/src/systemd/src/basic/hostname-util.h b/src/systemd/src/basic/hostname-util.h
index 749481723d..7ba386a0fd 100644
--- a/src/systemd/src/basic/hostname-util.h
+++ b/src/systemd/src/basic/hostname-util.h
@@ -11,6 +11,7 @@ bool hostname_is_set(void);
char* gethostname_malloc(void);
int gethostname_strict(char **ret);
+bool valid_ldh_char(char c) _const_;
bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
char* hostname_cleanup(char *s);
diff --git a/src/systemd/src/basic/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c
index 206e00ca93..0f2538e213 100644
--- a/src/systemd/src/basic/in-addr-util.c
+++ b/src/systemd/src/basic/in-addr-util.c
@@ -366,7 +366,7 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
assert(addr);
- return 32 - u32ctz(be32toh(addr->s_addr));
+ return 32U - u32ctz(be32toh(addr->s_addr));
}
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
@@ -608,15 +608,12 @@ int in_addr_prefix_from_string_auto_internal(
}
-void in_addr_data_hash_func(const void *p, struct siphash *state) {
- const struct in_addr_data *a = p;
-
+static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
siphash24_compress(&a->family, sizeof(a->family), state);
siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
}
-int in_addr_data_compare_func(const void *a, const void *b) {
- const struct in_addr_data *x = a, *y = b;
+static int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
int r;
r = CMP(x->family, y->family);
@@ -626,8 +623,5 @@ int in_addr_data_compare_func(const void *a, const void *b) {
return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
}
-const struct hash_ops in_addr_data_hash_ops = {
- .hash = in_addr_data_hash_func,
- .compare = in_addr_data_compare_func,
-};
+DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h
index 2f64c31f96..5de85cc422 100644
--- a/src/systemd/src/basic/in-addr-util.h
+++ b/src/systemd/src/basic/in-addr-util.h
@@ -69,6 +69,4 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
* See also oss-fuzz#11344. */
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
-void in_addr_data_hash_func(const void *p, struct siphash *state);
-int in_addr_data_compare_func(const void *a, const void *b);
extern const struct hash_ops in_addr_data_hash_ops;
diff --git a/src/systemd/src/basic/list.h b/src/systemd/src/basic/list.h
index 040680c30a..f7f97000e0 100644
--- a/src/systemd/src/basic/list.h
+++ b/src/systemd/src/basic/list.h
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "macro.h"
+
/* The head of the linked list. Use this in the structure that shall
* contain the head of the linked list */
#define LIST_HEAD(t,name) \
@@ -13,8 +15,8 @@
/* Initialize the list's head */
#define LIST_HEAD_INIT(head) \
do { \
- (head) = NULL; } \
- while (false)
+ (head) = NULL; \
+ } while (false)
/* Initialize a list item */
#define LIST_INIT(name,item) \
diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h
index d1775f2ae9..6a1fdab537 100644
--- a/src/systemd/src/basic/macro.h
+++ b/src/systemd/src/basic/macro.h
@@ -2,33 +2,38 @@
#pragma once
#include <assert.h>
+#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <sys/param.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
-#define _printf_(a, b) __attribute__ ((__format__(printf, a, b)))
+#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
#ifdef __clang__
# define _alloc_(...)
#else
-# define _alloc_(...) __attribute__ ((__alloc_size__(__VA_ARGS__)))
+# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
#endif
-#define _sentinel_ __attribute__ ((__sentinel__))
-#define _unused_ __attribute__ ((__unused__))
-#define _destructor_ __attribute__ ((__destructor__))
-#define _pure_ __attribute__ ((__pure__))
-#define _const_ __attribute__ ((__const__))
-#define _deprecated_ __attribute__ ((__deprecated__))
-#define _packed_ __attribute__ ((__packed__))
-#define _malloc_ __attribute__ ((__malloc__))
-#define _weak_ __attribute__ ((__weak__))
+#define _sentinel_ __attribute__((__sentinel__))
+#define _section_(x) __attribute__((__section__(x)))
+#define _used_ __attribute__((__used__))
+#define _unused_ __attribute__((__unused__))
+#define _destructor_ __attribute__((__destructor__))
+#define _pure_ __attribute__((__pure__))
+#define _const_ __attribute__((__const__))
+#define _deprecated_ __attribute__((__deprecated__))
+#define _packed_ __attribute__((__packed__))
+#define _malloc_ __attribute__((__malloc__))
+#define _weak_ __attribute__((__weak__))
#define _likely_(x) (__builtin_expect(!!(x), 1))
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
-#define _public_ __attribute__ ((__visibility__("default")))
-#define _hidden_ __attribute__ ((__visibility__("hidden")))
+#define _public_ __attribute__((__visibility__("default")))
+#define _hidden_ __attribute__((__visibility__("hidden")))
#define _weakref_(x) __attribute__((__weakref__(#x)))
+#define _align_(x) __attribute__((__aligned__(x)))
#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
+#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
#define _cleanup_(x) __attribute__((__cleanup__(x)))
#if __GNUC__ >= 7
#define _fallthrough_ __attribute__((__fallthrough__))
@@ -56,6 +61,29 @@
# endif
#endif
+#if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
+# ifdef __SANITIZE_ADDRESS__
+# define HAS_FEATURE_ADDRESS_SANITIZER 1
+# elif defined(__has_feature)
+# if __has_feature(address_sanitizer)
+# define HAS_FEATURE_ADDRESS_SANITIZER 1
+# endif
+# endif
+# if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
+# define HAS_FEATURE_ADDRESS_SANITIZER 0
+# endif
+#endif
+
+/* Note: on GCC "no_sanitize_address" is a function attribute only, on llvm it may also be applied to global
+ * variables. We define a specific macro which knows this. Note that on GCC we don't need this decorator so much, since
+ * our primary usecase for this attribute is registration structures placed in named ELF sections which shall not be
+ * padded, but GCC doesn't pad those anyway if AddressSanitizer is enabled. */
+#if HAS_FEATURE_ADDRESS_SANITIZER && defined(__clang__)
+#define _variable_no_sanitize_address_ __attribute__((__no_sanitize_address__))
+#else
+#define _variable_no_sanitize_address_
+#endif
+
#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__)
/* Temporarily disable some warnings */
#define DISABLE_WARNING_FORMAT_NONLITERAL \
@@ -255,11 +283,12 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
* computation should be possible in the given type. Therefore, we use
* [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the
* quotient and the remainder, so both should be equally fast. */
-#define DIV_ROUND_UP(_x, _y) \
+#define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y))
+#define __DIV_ROUND_UP(xq, x, yq, y) \
({ \
- const typeof(_x) __x = (_x); \
- const typeof(_y) __y = (_y); \
- (__x / __y + !!(__x % __y)); \
+ const typeof(x) UNIQ_T(X, xq) = (x); \
+ const typeof(y) UNIQ_T(Y, yq) = (y); \
+ (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \
})
#ifdef __COVERITY__
@@ -466,6 +495,11 @@ static inline int __coverity_check__(int condition) {
#endif
#endif
+#define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \
+ static inline void name(type *p) { \
+ func(p); \
+ }
+
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \
diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c
index 09ae085511..1f0b711113 100644
--- a/src/systemd/src/basic/parse-util.c
+++ b/src/systemd/src/basic/parse-util.c
@@ -4,6 +4,7 @@
#include <errno.h>
#include <inttypes.h>
+#include <linux/oom.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
@@ -18,10 +19,12 @@
#include "missing.h"
#include "parse-util.h"
#include "process-util.h"
+#include "stat-util.h"
#include "string-util.h"
int parse_boolean(const char *v) {
- assert(v);
+ if (!v)
+ return -EINVAL;
if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
return 1;
@@ -715,18 +718,51 @@ int parse_ip_port(const char *s, uint16_t *ret) {
return 0;
}
+int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
+ unsigned l, h;
+ int r;
+
+ r = parse_range(s, &l, &h);
+ if (r < 0)
+ return r;
+
+ if (l <= 0 || l > 65535 || h <= 0 || h > 65535)
+ return -EINVAL;
+
+ if (h < l)
+ return -EINVAL;
+
+ *low = l;
+ *high = h;
+
+ return 0;
+}
+
int parse_dev(const char *s, dev_t *ret) {
+ const char *major;
unsigned x, y;
- dev_t d;
+ size_t n;
+ int r;
- if (sscanf(s, "%u:%u", &x, &y) != 2)
+ n = strspn(s, DIGITS);
+ if (n == 0)
return -EINVAL;
-
- d = makedev(x, y);
- if ((unsigned) major(d) != x || (unsigned) minor(d) != y)
+ if (s[n] != ':')
return -EINVAL;
- *ret = d;
+ major = strndupa(s, n);
+ r = safe_atou(major, &x);
+ if (r < 0)
+ return r;
+
+ r = safe_atou(s + n + 1, &y);
+ if (r < 0)
+ return r;
+
+ if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
+ return -ERANGE;
+
+ *ret = makedev(x, y);
return 0;
}
diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h
index f3267f4cfe..e47641b429 100644
--- a/src/systemd/src/basic/parse-util.h
+++ b/src/systemd/src/basic/parse-util.h
@@ -115,5 +115,6 @@ int parse_permille(const char *p);
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_oom_score_adjust(const char *s, int *ret);
diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c
index dc37e04dd7..1446ecdc85 100644
--- a/src/systemd/src/basic/path-util.c
+++ b/src/systemd/src/basic/path-util.c
@@ -113,7 +113,7 @@ int path_make_absolute_cwd(const char *p, char **ret) {
if (r < 0)
return r;
- c = path_join(NULL, cwd, p);
+ c = path_join(cwd, p);
}
if (!c)
return -ENOMEM;
@@ -486,18 +486,62 @@ bool path_equal_or_files_same(const char *a, const char *b, int flags) {
return path_equal(a, b) || files_same(a, b, flags) > 0;
}
-char* path_join(const char *root, const char *path, const char *rest) {
- assert(path);
+char* path_join_internal(const char *first, ...) {
+ char *joined, *q;
+ const char *p;
+ va_list ap;
+ bool slash;
+ size_t sz;
+
+ /* Joins all listed strings until the sentinel and places a "/" between them unless the strings end/begin
+ * already with one so that it is unnecessary. Note that slashes which are already duplicate won't be
+ * removed. The string returned is hence always equal to or longer than the sum of the lengths of each
+ * individual string.
+ *
+ * Note: any listed empty string is simply skipped. This can be useful for concatenating strings of which some
+ * are optional.
+ *
+ * Examples:
+ *
+ * path_join("foo", "bar") → "foo/bar"
+ * path_join("foo/", "bar") → "foo/bar"
+ * path_join("", "foo", "", "bar", "") → "foo/bar" */
+
+ sz = strlen_ptr(first);
+ va_start(ap, first);
+ while ((p = va_arg(ap, char*)) != (const char*) -1)
+ if (!isempty(p))
+ sz += 1 + strlen(p);
+ va_end(ap);
+
+ joined = new(char, sz + 1);
+ if (!joined)
+ return NULL;
- if (!isempty(root))
- return strjoin(root, endswith(root, "/") ? "" : "/",
- path[0] == '/' ? path+1 : path,
- rest ? (endswith(path, "/") ? "" : "/") : NULL,
- rest && rest[0] == '/' ? rest+1 : rest);
- else
- return strjoin(path,
- rest ? (endswith(path, "/") ? "" : "/") : NULL,
- rest && rest[0] == '/' ? rest+1 : rest);
+ if (!isempty(first)) {
+ q = stpcpy(joined, first);
+ slash = endswith(first, "/");
+ } else {
+ /* Skip empty items */
+ joined[0] = 0;
+ q = joined;
+ slash = true; /* no need to generate a slash anymore */
+ }
+
+ va_start(ap, first);
+ while ((p = va_arg(ap, char*)) != (const char*) -1) {
+ if (isempty(p))
+ continue;
+
+ if (!slash && p[0] != '/')
+ *(q++) = '/';
+
+ q = stpcpy(q, p);
+ slash = endswith(p, "/");
+ }
+ va_end(ap);
+
+ return joined;
}
int find_binary(const char *name, char **ret) {
@@ -755,6 +799,9 @@ const char *last_path_component(const char *path) {
unsigned l, k;
+ if (!path)
+ return NULL;
+
l = k = strlen(path);
if (l == 0) /* special case — an empty string */
return path;
@@ -770,6 +817,37 @@ const char *last_path_component(const char *path) {
return path + k;
}
+
+int path_extract_filename(const char *p, char **ret) {
+ _cleanup_free_ char *a = NULL;
+ const char *c, *e = NULL, *q;
+
+ /* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes
+ * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing slashes. */
+
+ if (!p)
+ return -EINVAL;
+
+ c = last_path_component(p);
+
+ for (q = c; *q != 0; q++)
+ if (*q != '/')
+ e = q + 1;
+
+ if (!e) /* no valid character? */
+ return -EINVAL;
+
+ a = strndup(c, e - c);
+ if (!a)
+ return -ENOMEM;
+
+ if (!filename_is_valid(a))
+ return -EINVAL;
+
+ *ret = TAKE_PTR(a);
+
+ return 0;
+}
#endif /* NM_IGNORED */
bool filename_is_valid(const char *p) {
@@ -926,8 +1004,7 @@ bool valid_device_allow_pattern(const char *path) {
/* Like valid_device_node_path(), but also allows full-subsystem expressions, like DeviceAllow= and DeviceDeny=
* accept it */
- if (startswith(path, "block-") ||
- startswith(path, "char-"))
+ if (STARTSWITH_SET(path, "block-", "char-"))
return true;
return valid_device_node_path(path);
@@ -1071,6 +1148,13 @@ int path_simplify_and_warn(
return -EINVAL;
}
+ if (!path_is_valid(path)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s= path has invalid length (%zu bytes)%s.",
+ lvalue, strlen(path), fatal ? "" : ", ignoring");
+ return -EINVAL;
+ }
+
return 0;
}
#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h
index 4a4bd4cd51..56ebd59c6f 100644
--- a/src/systemd/src/basic/path-util.h
+++ b/src/systemd/src/basic/path-util.h
@@ -7,6 +7,7 @@
#include "macro.h"
#include "string-util.h"
+#include "strv.h"
#include "time-util.h"
#if 0 /* NM_IGNORED */
@@ -50,7 +51,9 @@ char* path_startswith(const char *path, const char *prefix) _pure_;
int path_compare(const char *a, const char *b) _pure_;
bool path_equal(const char *a, const char *b) _pure_;
bool path_equal_or_files_same(const char *a, const char *b, int flags);
-char* path_join(const char *root, const char *path, const char *rest);
+char* path_join_internal(const char *first, ...);
+#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, (const char*) -1)
+
char* path_simplify(char *path, bool kill_dots);
static inline bool path_equal_ptr(const char *a, const char *b) {
@@ -72,13 +75,13 @@ static inline bool path_equal_ptr(const char *a, const char *b) {
#define PATH_STARTSWITH_SET(p, ...) \
({ \
- char **s; \
- bool _found = false; \
- STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__)) \
- if (path_startswith(p, *s)) { \
- _found = true; \
- break; \
- } \
+ const char *_p = (p); \
+ char *_found = NULL, **_i; \
+ STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) { \
+ _found = path_startswith(_p, *_i); \
+ if (_found) \
+ break; \
+ } \
_found; \
})
@@ -96,12 +99,24 @@ int mkfs_exists(const char *fstype);
/* Iterates through the path prefixes of the specified path, going up
* the tree, to root. Also returns "" (and not "/"!) for the root
* directory. Excludes the specified directory itself */
-#define PATH_FOREACH_PREFIX(prefix, path) \
- for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+#define PATH_FOREACH_PREFIX(prefix, path) \
+ for (char *_slash = ({ \
+ path_simplify(strcpy(prefix, path), false); \
+ streq(prefix, "/") ? NULL : strrchr(prefix, '/'); \
+ }); \
+ _slash && ((*_slash = 0), true); \
+ _slash = strrchr((prefix), '/'))
/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
-#define PATH_FOREACH_PREFIX_MORE(prefix, path) \
- for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+#define PATH_FOREACH_PREFIX_MORE(prefix, path) \
+ for (char *_slash = ({ \
+ path_simplify(strcpy(prefix, path), false); \
+ if (streq(prefix, "/")) \
+ prefix[0] = 0; \
+ strrchr(prefix, 0); \
+ }); \
+ _slash && ((*_slash = 0), true); \
+ _slash = strrchr((prefix), '/'))
char *prefix_root(const char *root, const char *path);
@@ -134,6 +149,7 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar
char* dirname_malloc(const char *path);
const char *last_path_component(const char *path);
+int path_extract_filename(const char *p, char **ret);
bool filename_is_valid(const char *p) _pure_;
bool path_is_valid(const char *p) _pure_;
diff --git a/src/systemd/src/basic/prioq.c b/src/systemd/src/basic/prioq.c
index 3af3402504..14e29c52e4 100644
--- a/src/systemd/src/basic/prioq.c
+++ b/src/systemd/src/basic/prioq.c
@@ -67,9 +67,6 @@ int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) {
}
static void swap(Prioq *q, unsigned j, unsigned k) {
- void *saved_data;
- unsigned *saved_idx;
-
assert(q);
assert(j < q->n_items);
assert(k < q->n_items);
@@ -77,12 +74,8 @@ static void swap(Prioq *q, unsigned j, unsigned k) {
assert(!q->items[j].idx || *(q->items[j].idx) == j);
assert(!q->items[k].idx || *(q->items[k].idx) == k);
- saved_data = q->items[j].data;
- saved_idx = q->items[j].idx;
- q->items[j].data = q->items[k].data;
- q->items[j].idx = q->items[k].idx;
- q->items[k].data = saved_data;
- q->items[k].idx = saved_idx;
+ SWAP_TWO(q->items[j].data, q->items[k].data);
+ SWAP_TWO(q->items[j].idx, q->items[k].idx);
if (q->items[j].idx)
*q->items[j].idx = j;
diff --git a/src/systemd/src/basic/process-util.c b/src/systemd/src/basic/process-util.c
index 4171a23777..bf05b2e8ef 100644
--- a/src/systemd/src/basic/process-util.c
+++ b/src/systemd/src/basic/process-util.c
@@ -39,6 +39,7 @@
#include "missing.h"
#include "process-util.h"
#include "raw-clone.h"
+#include "rlimit-util.h"
#include "signal-util.h"
#include "stat-util.h"
#include "string-table.h"
@@ -604,12 +605,14 @@ int get_process_root(pid_t pid, char **root) {
return get_process_link_contents(p, root);
}
+#define ENVIRONMENT_BLOCK_MAX (5U*1024U*1024U)
+
int get_process_environ(pid_t pid, char **env) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *outcome = NULL;
- int c;
- const char *p;
size_t allocated = 0, sz = 0;
+ const char *p;
+ int r;
assert(pid >= 0);
assert(env);
@@ -625,23 +628,28 @@ int get_process_environ(pid_t pid, char **env) {
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
- while ((c = fgetc(f)) != EOF) {
+ for (;;) {
+ char c;
+
+ if (sz >= ENVIRONMENT_BLOCK_MAX)
+ return -ENOBUFS;
+
if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
return -ENOMEM;
+ r = safe_fgetc(f, &c);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
if (c == '\0')
outcome[sz++] = '\n';
else
sz += cescape_char(c, outcome + sz);
}
- if (!outcome) {
- outcome = strdup("");
- if (!outcome)
- return -ENOMEM;
- } else
- outcome[sz] = '\0';
-
+ outcome[sz] = '\0';
*env = TAKE_PTR(outcome);
return 0;
@@ -874,9 +882,9 @@ int kill_and_sigcont(pid_t pid, int sig) {
int getenv_for_pid(pid_t pid, const char *field, char **ret) {
_cleanup_fclose_ FILE *f = NULL;
char *value = NULL;
- bool done = false;
const char *path;
- size_t l;
+ size_t l, sum = 0;
+ int r;
assert(pid >= 0);
assert(field);
@@ -899,6 +907,9 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
return 1;
}
+ if (!pid_is_valid(pid))
+ return -EINVAL;
+
path = procfs_file_alloca(pid, "environ");
f = fopen(path, "re");
@@ -912,24 +923,19 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
l = strlen(field);
+ for (;;) {
+ _cleanup_free_ char *line = NULL;
- do {
- char line[LINE_MAX];
- size_t i;
-
- for (i = 0; i < sizeof(line)-1; i++) {
- int c;
+ if (sum > ENVIRONMENT_BLOCK_MAX) /* Give up searching eventually */
+ return -ENOBUFS;
- c = getc(f);
- if (_unlikely_(c == EOF)) {
- done = true;
- break;
- } else if (c == 0)
- break;
+ r = read_nul_string(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ return r;
+ if (r == 0) /* EOF */
+ break;
- line[i] = c;
- }
- line[i] = 0;
+ sum += r;
if (strneq(line, field, l) && line[l] == '=') {
value = strdup(line + l + 1);
@@ -939,8 +945,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
*ret = value;
return 1;
}
-
- } while (!done);
+ }
*ret = NULL;
return 0;
@@ -1180,7 +1185,7 @@ void reset_cached_pid(void) {
* headers. __register_atfork() is mostly equivalent to pthread_atfork(), but doesn't require us to link against
* libpthread, as it is part of glibc anyway. */
extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void), void *dso_handle);
-extern void* __dso_handle __attribute__ ((__weak__));
+extern void* __dso_handle _weak_;
pid_t getpid_cached(void) {
static bool installed = false;
@@ -1259,25 +1264,17 @@ int safe_fork_full(
original_pid = getpid_cached();
if (flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG)) {
-
/* We temporarily block all signals, so that the new child has them blocked initially. This way, we can
* be sure that SIGTERMs are not lost we might send to the child. */
- if (sigfillset(&ss) < 0)
- return log_full_errno(prio, errno, "Failed to reset signal set: %m");
-
+ assert_se(sigfillset(&ss) >= 0);
block_signals = true;
} else if (flags & FORK_WAIT) {
-
/* Let's block SIGCHLD at least, so that we can safely watch for the child process */
- if (sigemptyset(&ss) < 0)
- return log_full_errno(prio, errno, "Failed to clear signal set: %m");
-
- if (sigaddset(&ss, SIGCHLD) < 0)
- return log_full_errno(prio, errno, "Failed to add SIGCHLD to signal set: %m");
-
+ assert_se(sigemptyset(&ss) >= 0);
+ assert_se(sigaddset(&ss, SIGCHLD) >= 0);
block_signals = true;
}
@@ -1410,6 +1407,14 @@ int safe_fork_full(
}
}
+ if (flags & FORK_RLIMIT_NOFILE_SAFE) {
+ r = rlimit_nofile_safe();
+ if (r < 0) {
+ log_full_errno(prio, r, "Failed to lower RLIMIT_NOFILE's soft limit to 1K: %m");
+ _exit(EXIT_FAILURE);
+ }
+ }
+
if (ret_pid)
*ret_pid = getpid_cached();
@@ -1521,6 +1526,8 @@ int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret
safe_close_above_stdio(fd);
}
+ (void) rlimit_nofile_safe();
+
/* Count arguments */
va_start(ap, path);
for (n = 0; va_arg(ap, char*); n++)
diff --git a/src/systemd/src/basic/process-util.h b/src/systemd/src/basic/process-util.h
index fea152cecf..0fad4e1ee9 100644
--- a/src/systemd/src/basic/process-util.h
+++ b/src/systemd/src/basic/process-util.h
@@ -144,15 +144,16 @@ void reset_cached_pid(void);
int must_be_root(void);
typedef enum ForkFlags {
- FORK_RESET_SIGNALS = 1 << 0,
- FORK_CLOSE_ALL_FDS = 1 << 1,
- FORK_DEATHSIG = 1 << 2,
- FORK_NULL_STDIO = 1 << 3,
- FORK_REOPEN_LOG = 1 << 4,
- FORK_LOG = 1 << 5,
- FORK_WAIT = 1 << 6,
- FORK_NEW_MOUNTNS = 1 << 7,
- FORK_MOUNTNS_SLAVE = 1 << 8,
+ FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */
+ FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
+ FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child */
+ FORK_NULL_STDIO = 1 << 3, /* Connect 0,1,2 to /dev/null */
+ FORK_REOPEN_LOG = 1 << 4, /* Reopen log connection */
+ FORK_LOG = 1 << 5, /* Log above LOG_DEBUG log level about failures */
+ FORK_WAIT = 1 << 6, /* Wait until child exited */
+ FORK_NEW_MOUNTNS = 1 << 7, /* Run child in its own mount namespace */
+ FORK_MOUNTNS_SLAVE = 1 << 8, /* Make child's mount namespace MS_SLAVE */
+ FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
} ForkFlags;
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c
index f69ca0f0f4..39ca85eebb 100644
--- a/src/systemd/src/basic/random-util.c
+++ b/src/systemd/src/basic/random-util.c
@@ -9,7 +9,6 @@
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
-#include <linux/random.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/src/systemd/src/basic/set.h b/src/systemd/src/basic/set.h
index 0d99d5550d..2a80632b79 100644
--- a/src/systemd/src/basic/set.h
+++ b/src/systemd/src/basic/set.h
@@ -9,13 +9,11 @@ Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
static inline Set *set_free(Set *s) {
- internal_hashmap_free(HASHMAP_BASE(s));
- return NULL;
+ return (Set*) internal_hashmap_free(HASHMAP_BASE(s), NULL, NULL);
}
static inline Set *set_free_free(Set *s) {
- internal_hashmap_free_free(HASHMAP_BASE(s));
- return NULL;
+ return (Set*) internal_hashmap_free(HASHMAP_BASE(s), free, NULL);
}
/* no set_free_free_free */
@@ -76,11 +74,11 @@ static inline unsigned set_buckets(Set *s) {
bool set_iterate(Set *s, Iterator *i, void **value);
static inline void set_clear(Set *s) {
- internal_hashmap_clear(HASHMAP_BASE(s));
+ internal_hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
}
static inline void set_clear_free(Set *s) {
- internal_hashmap_clear_free(HASHMAP_BASE(s));
+ internal_hashmap_clear(HASHMAP_BASE(s), free, NULL);
}
/* no set_clear_free_free */
diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c
index 4476f3dc7a..7fcedf3714 100644
--- a/src/systemd/src/basic/socket-util.c
+++ b/src/systemd/src/basic/socket-util.c
@@ -17,6 +17,7 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-util.h"
@@ -114,7 +115,7 @@ int socket_address_parse(SocketAddress *a, const char *s) {
size_t l;
l = strlen(s+1);
- if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminate sockets here
+ 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
@@ -264,9 +265,12 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
return 0;
}
-int socket_address_verify(const SocketAddress *a) {
+int socket_address_verify(const SocketAddress *a, bool strict) {
assert(a);
+ /* With 'strict' we enforce additional sanity constraints which are not set by the standard,
+ * but should only apply to sockets we create ourselves. */
+
switch (socket_address_family(a)) {
case AF_INET:
@@ -296,19 +300,20 @@ int socket_address_verify(const SocketAddress *a) {
case AF_UNIX:
if (a->size < offsetof(struct sockaddr_un, sun_path))
return -EINVAL;
- if (a->size > sizeof(struct sockaddr_un)+1) /* Allow one extra byte, since getsockname() on Linux will
- * append a NUL byte if we have path sockets that are above
- * sun_path' full size */
+ if (a->size > sizeof(struct sockaddr_un) + !strict)
+ /* If !strict, allow one extra byte, since getsockname() on Linux will append
+ * a NUL byte if we have path sockets that are above sun_path's full size. */
return -EINVAL;
if (a->size > offsetof(struct sockaddr_un, sun_path) &&
- a->sockaddr.un.sun_path[0] != 0) { /* Only validate file system sockets here */
-
+ a->sockaddr.un.sun_path[0] != 0 &&
+ strict) {
+ /* Only validate file system sockets here, and only in strict mode */
const char *e;
e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
if (e) {
- /* If there's an embedded NUL byte, make sure the size of the socket addresses matches it */
+ /* If there's an embedded NUL byte, make sure the size of the socket address matches it */
if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
return -EINVAL;
} else {
@@ -356,7 +361,10 @@ int socket_address_print(const SocketAddress *a, char **ret) {
assert(a);
assert(ret);
- r = socket_address_verify(a);
+ r = socket_address_verify(a, false); /* We do non-strict validation, because we want to be
+ * able to pretty-print any socket the kernel considers
+ * valid. We still need to do validation to know if we
+ * can meaningfully print the address. */
if (r < 0)
return r;
@@ -389,8 +397,8 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
assert(b);
/* Invalid addresses are unequal to all */
- if (socket_address_verify(a) < 0 ||
- socket_address_verify(b) < 0)
+ if (socket_address_verify(a, false) < 0 ||
+ socket_address_verify(b, false) < 0)
return false;
if (a->type != b->type)
@@ -574,7 +582,13 @@ int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
}
}
-int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
+int sockaddr_pretty(
+ const struct sockaddr *_sa,
+ socklen_t salen,
+ bool translate_ipv6,
+ bool include_port,
+ char **ret) {
+
union sockaddr_union *sa = (union sockaddr_union*) _sa;
char *p;
int r;
@@ -645,42 +659,51 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
}
case AF_UNIX:
- if (salen <= offsetof(struct sockaddr_un, sun_path)) {
+ if (salen <= offsetof(struct sockaddr_un, sun_path) ||
+ (sa->un.sun_path[0] == 0 && salen == offsetof(struct sockaddr_un, sun_path) + 1))
+ /* The name must have at least one character (and the leading NUL does not count) */
p = strdup("<unnamed>");
- if (!p)
- return -ENOMEM;
-
- } else if (sa->un.sun_path[0] == 0) {
- /* abstract */
-
- /* FIXME: We assume we can print the
- * socket path here and that it hasn't
- * more than one NUL byte. That is
- * actually an invalid assumption */
-
- p = new(char, sizeof(sa->un.sun_path)+1);
- if (!p)
- return -ENOMEM;
+ else {
+ /* Note that we calculate the path pointer here through the .un_buffer[] field, in order to
+ * outtrick bounds checking tools such as ubsan, which are too smart for their own good: on
+ * Linux the kernel may return sun_path[] data one byte longer than the declared size of the
+ * field. */
+ char *path = (char*) sa->un_buffer + offsetof(struct sockaddr_un, sun_path);
+ size_t path_len = salen - offsetof(struct sockaddr_un, sun_path);
+
+ if (path[0] == 0) {
+ /* Abstract socket. When parsing address information from, we
+ * explicitly reject overly long paths and paths with embedded NULs.
+ * But we might get such a socket from the outside. Let's return
+ * something meaningful and printable in this case. */
+
+ _cleanup_free_ char *e = NULL;
+
+ e = cescape_length(path + 1, path_len - 1);
+ if (!e)
+ return -ENOMEM;
- p[0] = '@';
- memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
- p[sizeof(sa->un.sun_path)] = 0;
+ p = strjoin("@", e);
+ } else {
+ if (path[path_len - 1] == '\0')
+ /* We expect a terminating NUL and don't print it */
+ path_len --;
- } else {
- p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
- if (!p)
- return -ENOMEM;
+ p = cescape_length(path, path_len);
+ }
}
+ if (!p)
+ return -ENOMEM;
break;
case AF_VSOCK:
- if (include_port)
- r = asprintf(&p,
- "vsock:%u:%u",
- sa->vm.svm_cid,
- sa->vm.svm_port);
- else
+ if (include_port) {
+ if (sa->vm.svm_cid == VMADDR_CID_ANY)
+ r = asprintf(&p, "vsock::%u", sa->vm.svm_port);
+ else
+ r = asprintf(&p, "vsock:%u:%u", sa->vm.svm_cid, sa->vm.svm_port);
+ } else
r = asprintf(&p, "vsock:%u", sa->vm.svm_cid);
if (r < 0)
return -ENOMEM;
diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h
index 1ac30de5a3..d2246a8eb8 100644
--- a/src/systemd/src/basic/socket-util.h
+++ b/src/systemd/src/basic/socket-util.h
@@ -1,6 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include <inttypes.h>
+#include <linux/netlink.h>
+#include <linux/if_infiniband.h>
+#include <linux/if_packet.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <stdbool.h>
@@ -8,13 +12,10 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
-#include <linux/netlink.h>
-#include <linux/if_infiniband.h>
-#include <linux/if_packet.h>
#include "macro.h"
-#include "missing.h"
-#include "util.h"
+#include "missing_socket.h"
+#include "sparse-endian.h"
union sockaddr_union {
/* The minimal, abstract version */
@@ -72,7 +73,7 @@ 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) _pure_;
+int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
int sockaddr_un_unlink(const struct sockaddr_un *sa);
diff --git a/src/systemd/src/basic/stat-util.c b/src/systemd/src/basic/stat-util.c
index 8cae1e1e3f..e77f40aee5 100644
--- a/src/systemd/src/basic/stat-util.c
+++ b/src/systemd/src/basic/stat-util.c
@@ -12,11 +12,13 @@
#include <sys/types.h>
#include <unistd.h>
+#include "alloc-util.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "macro.h"
#include "missing.h"
+#include "parse-util.h"
#include "stat-util.h"
#include "string-util.h"
@@ -300,3 +302,124 @@ int fd_verify_regular(int fd) {
return stat_verify_regular(&st);
}
+
+#if 0 /* NM_IGNORED */
+int stat_verify_directory(const struct stat *st) {
+ assert(st);
+
+ if (S_ISLNK(st->st_mode))
+ return -ELOOP;
+
+ if (!S_ISDIR(st->st_mode))
+ return -ENOTDIR;
+
+ return 0;
+}
+
+int fd_verify_directory(int fd) {
+ struct stat st;
+
+ assert(fd >= 0);
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ return stat_verify_directory(&st);
+}
+
+int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) {
+ const char *t;
+
+ /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
+
+ if (S_ISCHR(mode))
+ t = "char";
+ else if (S_ISBLK(mode))
+ t = "block";
+ else
+ return -ENODEV;
+
+ if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0)
+ return -ENOMEM;
+
+ return 0;
+
+}
+
+int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
+
+ assert(ret);
+
+ if (major(devno) == 0 && minor(devno) == 0) {
+ char *s;
+
+ /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
+ * /dev/block/ and /dev/char/, hence we handle them specially here. */
+
+ if (S_ISCHR(mode))
+ s = strdup("/run/systemd/inaccessible/chr");
+ else if (S_ISBLK(mode))
+ s = strdup("/run/systemd/inaccessible/blk");
+ else
+ return -ENODEV;
+
+ if (!s)
+ return -ENOMEM;
+
+ *ret = s;
+ return 0;
+ }
+
+ r = device_path_make_major_minor(mode, devno, &p);
+ if (r < 0)
+ return r;
+
+ return chase_symlinks(p, NULL, 0, ret);
+}
+
+int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) {
+ mode_t mode;
+ dev_t devno;
+ int r;
+
+ /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
+ * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
+ * path cannot be parsed like this. */
+
+ if (path_equal(path, "/run/systemd/inaccessible/chr")) {
+ mode = S_IFCHR;
+ devno = makedev(0, 0);
+ } else if (path_equal(path, "/run/systemd/inaccessible/blk")) {
+ mode = S_IFBLK;
+ devno = makedev(0, 0);
+ } else {
+ const char *w;
+
+ w = path_startswith(path, "/dev/block/");
+ if (w)
+ mode = S_IFBLK;
+ else {
+ w = path_startswith(path, "/dev/char/");
+ if (!w)
+ return -ENODEV;
+
+ mode = S_IFCHR;
+ }
+
+ r = parse_dev(w, &devno);
+ if (r < 0)
+ return r;
+ }
+
+ if (ret_mode)
+ *ret_mode = mode;
+ if (ret_devno)
+ *ret_devno = devno;
+
+ return 0;
+}
+#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/stat-util.h b/src/systemd/src/basic/stat-util.h
index 1a725f1da0..0a08e642b5 100644
--- a/src/systemd/src/basic/stat-util.h
+++ b/src/systemd/src/basic/stat-util.h
@@ -59,3 +59,29 @@ int path_is_temporary_fs(const char *path);
int stat_verify_regular(const struct stat *st);
int fd_verify_regular(int fd);
+
+int stat_verify_directory(const struct stat *st);
+int fd_verify_directory(int fd);
+
+/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
+ * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
+ * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
+ * comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as
+ * such a test would be pointless in such a case.) */
+
+#define DEVICE_MAJOR_VALID(x) \
+ ({ \
+ typeof(x) _x = (x), _y = 0; \
+ _x >= _y && _x < (UINT32_C(1) << 12); \
+ \
+ })
+
+#define DEVICE_MINOR_VALID(x) \
+ ({ \
+ typeof(x) _x = (x), _y = 0; \
+ _x >= _y && _x < (UINT32_C(1) << 20); \
+ })
+
+int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret);
+int device_path_make_canonical(mode_t mode, dev_t devno, char **ret);
+int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno);
diff --git a/src/systemd/src/basic/strv.h b/src/systemd/src/basic/strv.h
index 5f1803d87d..aa4cd4aaca 100644
--- a/src/systemd/src/basic/strv.h
+++ b/src/systemd/src/basic/strv.h
@@ -144,6 +144,18 @@ void strv_print(char **l);
_x && strv_contains(STRV_MAKE(__VA_ARGS__), _x); \
})
+#define STARTSWITH_SET(p, ...) \
+ ({ \
+ const char *_p = (p); \
+ char *_found = NULL, **_i; \
+ STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) { \
+ _found = startswith(_p, *_i); \
+ if (_found) \
+ break; \
+ } \
+ _found; \
+ })
+
#define FOREACH_STRING(x, ...) \
for (char **_l = ({ \
char **_ll = STRV_MAKE(__VA_ARGS__); \
diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c
index 3465932f89..a2f616d148 100644
--- a/src/systemd/src/basic/time-util.c
+++ b/src/systemd/src/basic/time-util.c
@@ -22,6 +22,7 @@
#include "io-util.h"
#include "log.h"
#include "macro.h"
+#include "missing_timerfd.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
@@ -1391,9 +1392,7 @@ int get_timezone(char **tz) {
if (r < 0)
return r; /* returns EINVAL if not a symlink */
- e = path_startswith(t, "/usr/share/zoneinfo/");
- if (!e)
- e = path_startswith(t, "../usr/share/zoneinfo/");
+ e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
if (!e)
return -EINVAL;
diff --git a/src/systemd/src/basic/tmpfile-util.c b/src/systemd/src/basic/tmpfile-util.c
new file mode 100644
index 0000000000..b40da5dc8d
--- /dev/null
+++ b/src/systemd/src/basic/tmpfile-util.c
@@ -0,0 +1,335 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "nm-sd-adapt.h"
+
+#include <sys/mman.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "hexdecoct.h"
+#include "macro.h"
+#include "memfd-util.h"
+#include "missing_syscall.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "random-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "tmpfile-util.h"
+#include "umask-util.h"
+
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
+ FILE *f;
+ char *t;
+ int r, fd;
+
+ assert(path);
+ assert(_f);
+ assert(_temp_path);
+
+ r = tempfn_xxxxxx(path, NULL, &t);
+ if (r < 0)
+ return r;
+
+ fd = mkostemp_safe(t);
+ if (fd < 0) {
+ free(t);
+ return -errno;
+ }
+
+ f = fdopen(fd, "w");
+ if (!f) {
+ unlink_noerrno(t);
+ free(t);
+ safe_close(fd);
+ return -errno;
+ }
+
+ *_f = f;
+ *_temp_path = t;
+
+ return 0;
+}
+
+/* This is much like mkostemp() but is subject to umask(). */
+int mkostemp_safe(char *pattern) {
+ _cleanup_umask_ mode_t u = 0;
+ int fd;
+
+ assert(pattern);
+
+ u = umask(077);
+
+ fd = mkostemp(pattern, O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ return fd;
+}
+
+#if 0 /* NM_IGNORED */
+int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
+ int fd;
+ FILE *f;
+
+ fd = mkostemp_safe(pattern);
+ if (fd < 0)
+ return fd;
+
+ f = fdopen(fd, mode);
+ if (!f) {
+ safe_close(fd);
+ return -errno;
+ }
+
+ *ret_f = f;
+ return 0;
+}
+#endif /* NM_IGNORED */
+
+int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
+ const char *fn;
+ char *t;
+
+ assert(ret);
+
+ if (isempty(p))
+ return -EINVAL;
+ if (path_equal(p, "/"))
+ return -EINVAL;
+
+ /*
+ * Turns this:
+ * /foo/bar/waldo
+ *
+ * Into this:
+ * /foo/bar/.#<extra>waldoXXXXXX
+ */
+
+ fn = basename(p);
+ if (!filename_is_valid(fn))
+ return -EINVAL;
+
+ extra = strempty(extra);
+
+ t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
+ if (!t)
+ return -ENOMEM;
+
+ strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
+
+ *ret = path_simplify(t, false);
+ return 0;
+}
+
+#if 0 /* NM_IGNORED */
+int tempfn_random(const char *p, const char *extra, char **ret) {
+ const char *fn;
+ char *t, *x;
+ uint64_t u;
+ unsigned i;
+
+ assert(ret);
+
+ if (isempty(p))
+ return -EINVAL;
+ if (path_equal(p, "/"))
+ return -EINVAL;
+
+ /*
+ * Turns this:
+ * /foo/bar/waldo
+ *
+ * Into this:
+ * /foo/bar/.#<extra>waldobaa2a261115984a9
+ */
+
+ fn = basename(p);
+ if (!filename_is_valid(fn))
+ return -EINVAL;
+
+ extra = strempty(extra);
+
+ t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
+ if (!t)
+ return -ENOMEM;
+
+ x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
+
+ u = random_u64();
+ for (i = 0; i < 16; i++) {
+ *(x++) = hexchar(u & 0xF);
+ u >>= 4;
+ }
+
+ *x = 0;
+
+ *ret = path_simplify(t, false);
+ return 0;
+}
+
+int tempfn_random_child(const char *p, const char *extra, char **ret) {
+ char *t, *x;
+ uint64_t u;
+ unsigned i;
+ int r;
+
+ assert(ret);
+
+ /* Turns this:
+ * /foo/bar/waldo
+ * Into this:
+ * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
+ */
+
+ if (!p) {
+ r = tmp_dir(&p);
+ if (r < 0)
+ return r;
+ }
+
+ extra = strempty(extra);
+
+ t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
+ if (!t)
+ return -ENOMEM;
+
+ if (isempty(p))
+ x = stpcpy(stpcpy(t, ".#"), extra);
+ else
+ x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
+
+ u = random_u64();
+ for (i = 0; i < 16; i++) {
+ *(x++) = hexchar(u & 0xF);
+ u >>= 4;
+ }
+
+ *x = 0;
+
+ *ret = path_simplify(t, false);
+ return 0;
+}
+
+int open_tmpfile_unlinkable(const char *directory, int flags) {
+ char *p;
+ int fd, r;
+
+ if (!directory) {
+ r = tmp_dir(&directory);
+ if (r < 0)
+ return r;
+ } else if (isempty(directory))
+ return -EINVAL;
+
+ /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
+
+ /* Try O_TMPFILE first, if it is supported */
+ fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
+ if (fd >= 0)
+ return fd;
+
+ /* Fall back to unguessable name + unlinking */
+ p = strjoina(directory, "/systemd-tmp-XXXXXX");
+
+ fd = mkostemp_safe(p);
+ if (fd < 0)
+ return fd;
+
+ (void) unlink(p);
+
+ return fd;
+}
+
+int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
+ _cleanup_free_ char *tmp = NULL;
+ int r, fd;
+
+ assert(target);
+ assert(ret_path);
+
+ /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
+ assert((flags & O_EXCL) == 0);
+
+ /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
+ * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
+ * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
+
+ fd = open_parent(target, O_TMPFILE|flags, 0640);
+ if (fd >= 0) {
+ *ret_path = NULL;
+ return fd;
+ }
+
+ log_debug_errno(fd, "Failed to use O_TMPFILE for %s: %m", target);
+
+ r = tempfn_random(target, NULL, &tmp);
+ if (r < 0)
+ return r;
+
+ fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
+ if (fd < 0)
+ return -errno;
+
+ *ret_path = TAKE_PTR(tmp);
+
+ return fd;
+}
+
+int link_tmpfile(int fd, const char *path, const char *target) {
+ int r;
+
+ assert(fd >= 0);
+ assert(target);
+
+ /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
+ * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
+ * on the directory, and renameat2() is used instead.
+ *
+ * Note that in both cases we will not replace existing files. This is because linkat() does not support this
+ * operation currently (renameat2() does), and there is no nice way to emulate this. */
+
+ if (path) {
+ r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
+ if (r < 0)
+ return r;
+ } else {
+ char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
+
+ xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
+
+ if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
+ return -errno;
+ }
+
+ return 0;
+}
+
+int mkdtemp_malloc(const char *template, char **ret) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ assert(ret);
+
+ if (template)
+ p = strdup(template);
+ else {
+ const char *tmp;
+
+ r = tmp_dir(&tmp);
+ if (r < 0)
+ return r;
+
+ p = strjoin(tmp, "/XXXXXX");
+ }
+ if (!p)
+ return -ENOMEM;
+
+ if (!mkdtemp(p))
+ return -errno;
+
+ *ret = TAKE_PTR(p);
+ return 0;
+}
+#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/tmpfile-util.h b/src/systemd/src/basic/tmpfile-util.h
new file mode 100644
index 0000000000..802c85d6d9
--- /dev/null
+++ b/src/systemd/src/basic/tmpfile-util.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdio.h>
+
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
+int mkostemp_safe(char *pattern);
+int fmkostemp_safe(char *pattern, const char *mode, FILE**_f);
+
+int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
+int tempfn_random(const char *p, const char *extra, char **ret);
+int tempfn_random_child(const char *p, const char *extra, char **ret);
+
+int open_tmpfile_unlinkable(const char *directory, int flags);
+int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
+
+int link_tmpfile(int fd, const char *path, const char *target);
+
+int mkdtemp_malloc(const char *template, char **ret);
diff --git a/src/systemd/src/basic/utf8.h b/src/systemd/src/basic/utf8.h
index 628680ef53..eedfebe39c 100644
--- a/src/systemd/src/basic/utf8.h
+++ b/src/systemd/src/basic/utf8.h
@@ -9,7 +9,7 @@
#endif /* NM_IGNORED */
#include "macro.h"
-#include "missing.h"
+#include "missing_type.h"
#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd"
#define UTF8_BYTE_ORDER_MARK "\xef\xbb\xbf"
diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c
index ae8f0cad7c..382e95a072 100644
--- a/src/systemd/src/basic/util.c
+++ b/src/systemd/src/basic/util.c
@@ -25,6 +25,7 @@
#include "def.h"
#include "device-nodes.h"
#include "dirent-util.h"
+#include "env-file.h"
#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h
index 2f3d1eeab8..f009d37d4c 100644
--- a/src/systemd/src/basic/util.h
+++ b/src/systemd/src/basic/util.h
@@ -25,7 +25,6 @@
#include "format-util.h"
#include "macro.h"
-#include "missing.h"
#include "time-util.h"
size_t page_size(void) _pure_;
@@ -148,6 +147,12 @@ static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
return memcmp(s1, s2, n);
}
+/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
+static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
+ return memcmp_safe(s1, s2, MIN(n1, n2))
+ ?: CMP(n1, n2);
+}
+
int on_ac_power(void);
#define memzero(x,l) \
@@ -173,7 +178,7 @@ static inline void _reset_errno_(int *saved_errno) {
}
#define PROTECT_ERRNO \
- _cleanup_(_reset_errno_) __attribute__((__unused__)) int _saved_errno_ = errno
+ _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
static inline int negative_errno(void) {
/* This helper should be used to shut up gcc if you know 'errno' is
@@ -194,7 +199,7 @@ static inline unsigned u64log2(uint64_t n) {
static inline unsigned u32ctz(uint32_t n) {
#if __SIZEOF_INT__ == 4
- return __builtin_ctz(n);
+ return n != 0 ? __builtin_ctz(n) : 32;
#else
#error "Wut?"
#endif
diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c
index e58045d6e9..c2627bbe6e 100644
--- a/src/systemd/src/libsystemd-network/lldp-neighbor.c
+++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c
@@ -9,11 +9,11 @@
#include "in-addr-util.h"
#include "lldp-internal.h"
#include "lldp-neighbor.h"
+#include "missing.h"
#include "unaligned.h"
+#include "util.h"
-static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) {
- const LLDPNeighborID *id = p;
-
+static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
siphash24_compress(id->chassis_id, id->chassis_id_size, state);
siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state);
siphash24_compress(id->port_id, id->port_id_size, state);
@@ -21,27 +21,12 @@ static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) {
}
int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) {
- int r;
-
- r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size));
- if (r != 0)
- return r;
-
- r = CMP(x->chassis_id_size, y->chassis_id_size);
- if (r != 0)
- return r;
-
- r = memcmp(x->port_id, y->port_id, MIN(x->port_id_size, y->port_id_size));
- if (r != 0)
- return r;
-
- return CMP(x->port_id_size, y->port_id_size);
+ return memcmp_nn(x->chassis_id, x->chassis_id_size, y->chassis_id, y->chassis_id_size)
+ ?: memcmp_nn(x->port_id, x->port_id_size, y->port_id, y->port_id_size);
}
-const struct hash_ops lldp_neighbor_id_hash_ops = {
- .hash = lldp_neighbor_id_hash_func,
- .compare = (__compar_fn_t) lldp_neighbor_id_compare_func,
-};
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(lldp_neighbor_hash_ops, LLDPNeighborID, lldp_neighbor_id_hash_func, lldp_neighbor_id_compare_func,
+ sd_lldp_neighbor, lldp_neighbor_unlink);
int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
const sd_lldp_neighbor *x = a, *y = b;
@@ -99,7 +84,12 @@ sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) {
if (!n->lldp)
return NULL;
- assert_se(hashmap_remove(n->lldp->neighbor_by_id, &n->id) == n);
+ /* Only remove the neighbor object from the hash table if it's in there, don't complain if it isn't. This is
+ * because we are used as destructor call for hashmap_clear() and thus sometimes are called to de-register
+ * ourselves from the hashtable and sometimes are called after we already are de-registered. */
+
+ (void) hashmap_remove_value(n->lldp->neighbor_by_id, &n->id, n);
+
assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0);
n->lldp = NULL;
diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.h b/src/systemd/src/libsystemd-network/lldp-neighbor.h
index 2241c3bd9d..62dbff42ca 100644
--- a/src/systemd/src/libsystemd-network/lldp-neighbor.h
+++ b/src/systemd/src/libsystemd-network/lldp-neighbor.h
@@ -80,7 +80,7 @@ static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) {
return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2;
}
-extern const struct hash_ops lldp_neighbor_id_hash_ops;
+extern const struct hash_ops lldp_neighbor_hash_ops;
int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y);
int lldp_neighbor_prioq_compare_func(const void *a, const void *b);
diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c
index db779aaa81..c2af0368c1 100644
--- a/src/systemd/src/libsystemd-network/lldp-network.c
+++ b/src/systemd/src/libsystemd-network/lldp-network.c
@@ -7,6 +7,7 @@
#include "fd-util.h"
#include "lldp-network.h"
+#include "missing.h"
#include "socket-util.h"
int lldp_network_bind_raw_socket(int ifindex) {
diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c
index b2461b99e4..520f0783c3 100644
--- a/src/systemd/src/libsystemd-network/network-internal.c
+++ b/src/systemd/src/libsystemd-network/network-internal.c
@@ -374,36 +374,6 @@ int config_parse_hwaddrs(const char *unit,
return 0;
}
-int config_parse_iaid(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
- uint32_t iaid;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = safe_atou32(rvalue, &iaid);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Unable to read IAID, ignoring assignment: %s", rvalue);
- return 0;
- }
-
- *((uint32_t *)data) = iaid;
-
- return 0;
-}
-
int config_parse_bridge_port_priority(
const char *unit,
const char *filename,
diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h
index 06d6118448..dfe4c4244b 100644
--- a/src/systemd/src/libsystemd-network/network-internal.h
+++ b/src/systemd/src/libsystemd-network/network-internal.h
@@ -36,7 +36,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr);
CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs);
CONFIG_PARSER_PROTOTYPE(config_parse_ifnames);
CONFIG_PARSER_PROTOTYPE(config_parse_ifalias);
-CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority);
int net_get_unique_predictable_data(sd_device *device, uint64_t *result);
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
index 6ca6bcab53..aac24767c8 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
@@ -25,10 +25,11 @@
#include "dns-domain.h"
#include "event-util.h"
#include "hostname-util.h"
+#include "io-util.h"
#include "random-util.h"
#include "string-util.h"
-#include "util.h"
#include "strv.h"
+#include "util.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
@@ -343,8 +344,9 @@ int sd_dhcp_client_set_client_id(
*/
static int dhcp_client_set_iaid_duid_internal(
sd_dhcp_client *client,
+ bool iaid_append,
+ bool iaid_set,
uint32_t iaid,
- bool append_iaid,
uint16_t duid_type,
const void *duid,
size_t duid_len,
@@ -366,17 +368,17 @@ static int dhcp_client_set_iaid_duid_internal(
zero(client->client_id);
client->client_id.type = 255;
- if (append_iaid) {
- /* If IAID is not configured, generate it. */
- if (iaid == 0) {
+ if (iaid_append) {
+ if (iaid_set)
+ client->client_id.ns.iaid = htobe32(iaid);
+ else {
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
client->mac_addr_len,
true,
&client->client_id.ns.iaid);
if (r < 0)
return r;
- } else
- client->client_id.ns.iaid = htobe32(iaid);
+ }
}
if (duid != NULL) {
@@ -416,10 +418,10 @@ static int dhcp_client_set_iaid_duid_internal(
}
client->client_id_len = sizeof(client->client_id.type) + len +
- (append_iaid ? sizeof(client->client_id.ns.iaid) : 0);
+ (iaid_append ? sizeof(client->client_id.ns.iaid) : 0);
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
- log_dhcp_client(client, "Configured %sDUID, restarting.", append_iaid ? "IAID+" : "");
+ log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : "");
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
sd_dhcp_client_start(client);
}
@@ -429,18 +431,20 @@ static int dhcp_client_set_iaid_duid_internal(
int sd_dhcp_client_set_iaid_duid(
sd_dhcp_client *client,
+ bool iaid_set,
uint32_t iaid,
uint16_t duid_type,
const void *duid,
size_t duid_len) {
- return dhcp_client_set_iaid_duid_internal(client, iaid, true, duid_type, duid, duid_len, 0);
+ return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, duid_type, duid, duid_len, 0);
}
int sd_dhcp_client_set_iaid_duid_llt(
sd_dhcp_client *client,
+ bool iaid_set,
uint32_t iaid,
usec_t llt_time) {
- return dhcp_client_set_iaid_duid_internal(client, iaid, true, DUID_TYPE_LLT, NULL, 0, llt_time);
+ return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time);
}
int sd_dhcp_client_set_duid(
@@ -448,13 +452,13 @@ int sd_dhcp_client_set_duid(
uint16_t duid_type,
const void *duid,
size_t duid_len) {
- return dhcp_client_set_iaid_duid_internal(client, 0, false, duid_type, duid, duid_len, 0);
+ return dhcp_client_set_iaid_duid_internal(client, false, false, 0, duid_type, duid, duid_len, 0);
}
int sd_dhcp_client_set_duid_llt(
sd_dhcp_client *client,
usec_t llt_time) {
- return dhcp_client_set_iaid_duid_internal(client, 0, false, DUID_TYPE_LLT, NULL, 0, llt_time);
+ return dhcp_client_set_iaid_duid_internal(client, false, false, 0, DUID_TYPE_LLT, NULL, 0, llt_time);
}
#endif /* NM_IGNORED */
@@ -1784,8 +1788,7 @@ static int client_receive_message_raw(
if (!packet)
return -ENOMEM;
- iov.iov_base = packet;
- iov.iov_len = buflen;
+ iov = IOVEC_MAKE(packet, buflen);
len = recvmsg(fd, &msg, 0);
if (len < 0) {
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
index b953efc3df..b95ad0c978 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
@@ -18,6 +18,7 @@
#include "dhcp-lease-internal.h"
#include "dhcp-protocol.h"
#include "dns-domain.h"
+#include "env-file.h"
#include "fd-util.h"
#include "fileio.h"
#include "hexdecoct.h"
@@ -28,6 +29,7 @@
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
+#include "tmpfile-util.h"
#include "unaligned.h"
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
@@ -355,7 +357,7 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
return 0;
}
- r = dns_name_normalize(name, &normalized);
+ r = dns_name_normalize(name, 0, &normalized);
if (r < 0)
return r;
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
index 8c9fb932bc..63b7cf2b71 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -58,7 +58,7 @@ struct sd_dhcp6_client {
struct sd_dhcp6_lease *lease;
int fd;
bool information_request;
- bool has_iaid;
+ bool iaid_set;
be16_t *req_opts;
size_t req_opts_allocated;
size_t req_opts_len;
@@ -278,7 +278,7 @@ int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
client->ia_na.ia_na.id = htobe32(iaid);
client->ia_pd.ia_pd.id = htobe32(iaid);
- client->has_iaid = true;
+ client->iaid_set = true;
return 0;
}
@@ -802,7 +802,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
assert(client);
- if (client->has_iaid)
+ if (client->iaid_set)
return 0;
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, true, &iaid);
@@ -811,7 +811,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
client->ia_na.ia_na.id = iaid;
client->ia_pd.ia_pd.id = iaid;
- client->has_iaid = true;
+ client->iaid_set = true;
return 0;
}
diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c
index 6715f89420..72cb6e8bd5 100644
--- a/src/systemd/src/libsystemd-network/sd-lldp.c
+++ b/src/systemd/src/libsystemd-network/sd-lldp.c
@@ -4,6 +4,7 @@
#include <arpa/inet.h>
#include <linux/sockios.h>
+#include <sys/ioctl.h>
#include "sd-lldp.h"
@@ -29,12 +30,9 @@ static const char * const lldp_event_table[_SD_LLDP_EVENT_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event);
static void lldp_flush_neighbors(sd_lldp *lldp) {
- sd_lldp_neighbor *n;
-
assert(lldp);
- while ((n = hashmap_first(lldp->neighbor_by_id)))
- lldp_neighbor_unlink(n);
+ hashmap_clear(lldp->neighbor_by_id);
}
static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
@@ -377,7 +375,7 @@ _public_ int sd_lldp_new(sd_lldp **ret) {
.capability_mask = (uint16_t) -1,
};
- lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops);
+ lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_hash_ops);
if (!lldp->neighbor_by_id)
return -ENOMEM;
diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c
index 8e221ceedd..fc8c5148ee 100644
--- a/src/systemd/src/libsystemd/sd-event/sd-event.c
+++ b/src/systemd/src/libsystemd/sd-event/sd-event.c
@@ -1375,8 +1375,7 @@ static int event_make_inotify_data(
return 1;
}
-static int inode_data_compare(const void *a, const void *b) {
- const struct inode_data *x = a, *y = b;
+static int inode_data_compare(const struct inode_data *x, const struct inode_data *y) {
int r;
assert(x);
@@ -1389,19 +1388,14 @@ static int inode_data_compare(const void *a, const void *b) {
return CMP(x->ino, y->ino);
}
-static void inode_data_hash_func(const void *p, struct siphash *state) {
- const struct inode_data *d = p;
-
- assert(p);
+static void inode_data_hash_func(const struct inode_data *d, struct siphash *state) {
+ assert(d);
siphash24_compress(&d->dev, sizeof(d->dev), state);
siphash24_compress(&d->ino, sizeof(d->ino), state);
}
-const struct hash_ops inode_data_hash_ops = {
- .hash = inode_data_hash_func,
- .compare = inode_data_compare
-};
+DEFINE_PRIVATE_HASH_OPS(inode_data_hash_ops, struct inode_data, inode_data_hash_func, inode_data_compare);
static void event_free_inode_data(
sd_event *e,
diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c
index d4d668e885..1e654f0ea4 100644
--- a/src/systemd/src/libsystemd/sd-id128/id128-util.c
+++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c
@@ -187,16 +187,13 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
return id128_write_fd(fd, f, id, do_sync);
}
-void id128_hash_func(const void *p, struct siphash *state) {
- siphash24_compress(p, 16, state);
+void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
+ siphash24_compress(p, sizeof(sd_id128_t), state);
}
-int id128_compare_func(const void *a, const void *b) {
+int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
return memcmp(a, b, 16);
}
-const struct hash_ops id128_hash_ops = {
- .hash = id128_hash_func,
- .compare = id128_compare_func,
-};
+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 44f159c0b6..65f14ab252 100644
--- a/src/systemd/src/libsystemd/sd-id128/id128-util.h
+++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h
@@ -28,6 +28,6 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret);
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync);
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
-void id128_hash_func(const void *p, struct siphash *state);
-int id128_compare_func(const void *a, const void *b) _pure_;
+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;
diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c
index bede1db6d5..ccf6298eea 100644
--- a/src/systemd/src/shared/dns-domain.c
+++ b/src/systemd/src/shared/dns-domain.c
@@ -21,6 +21,7 @@
#include "dns-domain.h"
#include "hashmap.h"
#include "hexdecoct.h"
+#include "hostname-util.h"
#include "in-addr-util.h"
#include "macro.h"
#include "parse-util.h"
@@ -28,9 +29,9 @@
#include "strv.h"
#include "utf8.h"
-int dns_label_unescape(const char **name, char *dest, size_t sz) {
+int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags) {
const char *n;
- char *d;
+ char *d, last_char = 0;
int r = 0;
assert(name);
@@ -40,13 +41,15 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
d = dest;
for (;;) {
- if (*n == '.') {
- n++;
- break;
- }
+ if (*n == 0 || *n == '.') {
+ if (FLAGS_SET(flags, DNS_LABEL_LDH) && last_char == '-')
+ /* Trailing dash */
+ return -EINVAL;
- if (*n == 0)
+ if (*n == '.')
+ n++;
break;
+ }
if (r >= DNS_LABEL_MAX)
return -EINVAL;
@@ -56,6 +59,8 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
if (*n == '\\') {
/* Escaped character */
+ if (FLAGS_SET(flags, DNS_LABEL_NO_ESCAPES))
+ return -EINVAL;
n++;
@@ -66,6 +71,10 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
else if (IN_SET(*n, '\\', '.')) {
/* Escaped backslash or dot */
+ if (FLAGS_SET(flags, DNS_LABEL_LDH))
+ return -EINVAL;
+
+ last_char = *n;
if (d)
*(d++) = *n;
sz--;
@@ -94,6 +103,11 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
if (k > 255)
return -EINVAL;
+ if (FLAGS_SET(flags, DNS_LABEL_LDH) &&
+ !valid_ldh_char((char) k))
+ return -EINVAL;
+
+ last_char = (char) k;
if (d)
*(d++) = (char) k;
sz--;
@@ -107,6 +121,15 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
/* Normal character */
+ if (FLAGS_SET(flags, DNS_LABEL_LDH)) {
+ if (!valid_ldh_char(*n))
+ return -EINVAL;
+ if (r == 0 && *n == '-')
+ /* Leading dash */
+ return -EINVAL;
+ }
+
+ last_char = *n;
if (d)
*(d++) = *n;
sz--;
@@ -189,7 +212,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
terminal--;
}
- r = dns_label_unescape(&name, dest, sz);
+ r = dns_label_unescape(&name, dest, sz, 0);
if (r < 0)
return r;
@@ -386,7 +409,7 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
#endif
#endif /* NM_IGNORED */
-int dns_name_concat(const char *a, const char *b, char **_ret) {
+int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_ret) {
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
const char *p;
@@ -403,7 +426,7 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
for (;;) {
char label[DNS_LABEL_MAX];
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, flags);
if (r < 0)
return r;
if (r == 0) {
@@ -469,8 +492,7 @@ finish:
}
#if 0 /* NM_IGNORED */
-void dns_name_hash_func(const void *s, struct siphash *state) {
- const char *p = s;
+void dns_name_hash_func(const char *p, struct siphash *state) {
int r;
assert(p);
@@ -478,7 +500,7 @@ void dns_name_hash_func(const void *s, struct siphash *state) {
for (;;) {
char label[DNS_LABEL_MAX+1];
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r < 0)
break;
if (r == 0)
@@ -493,15 +515,15 @@ void dns_name_hash_func(const void *s, struct siphash *state) {
string_hash_func("", state);
}
-int dns_name_compare_func(const void *a, const void *b) {
+int dns_name_compare_func(const char *a, const char *b) {
const char *x, *y;
int r, q;
assert(a);
assert(b);
- x = (const char *) a + strlen(a);
- y = (const char *) b + strlen(b);
+ x = a + strlen(a);
+ y = b + strlen(b);
for (;;) {
char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
@@ -520,10 +542,7 @@ int dns_name_compare_func(const void *a, const void *b) {
}
}
-const struct hash_ops dns_name_hash_ops = {
- .hash = dns_name_hash_func,
- .compare = dns_name_compare_func
-};
+DEFINE_HASH_OPS(dns_name_hash_ops, char, dns_name_hash_func, dns_name_compare_func);
int dns_name_equal(const char *x, const char *y) {
int r, q;
@@ -534,11 +553,11 @@ int dns_name_equal(const char *x, const char *y) {
for (;;) {
char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
- r = dns_label_unescape(&x, la, sizeof(la));
+ r = dns_label_unescape(&x, la, sizeof la, 0);
if (r < 0)
return r;
- q = dns_label_unescape(&y, lb, sizeof(lb));
+ q = dns_label_unescape(&y, lb, sizeof lb, 0);
if (q < 0)
return q;
@@ -565,14 +584,14 @@ int dns_name_endswith(const char *name, const char *suffix) {
for (;;) {
char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
- r = dns_label_unescape(&n, ln, sizeof(ln));
+ r = dns_label_unescape(&n, ln, sizeof ln, 0);
if (r < 0)
return r;
if (!saved_n)
saved_n = n;
- q = dns_label_unescape(&s, ls, sizeof(ls));
+ q = dns_label_unescape(&s, ls, sizeof ls, 0);
if (q < 0)
return q;
@@ -603,13 +622,13 @@ int dns_name_startswith(const char *name, const char *prefix) {
for (;;) {
char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX];
- r = dns_label_unescape(&p, lp, sizeof(lp));
+ r = dns_label_unescape(&p, lp, sizeof lp, 0);
if (r < 0)
return r;
if (r == 0)
return true;
- q = dns_label_unescape(&n, ln, sizeof(ln));
+ q = dns_label_unescape(&n, ln, sizeof ln, 0);
if (q < 0)
return q;
@@ -638,14 +657,14 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
if (!saved_before)
saved_before = n;
- r = dns_label_unescape(&n, ln, sizeof(ln));
+ r = dns_label_unescape(&n, ln, sizeof ln, 0);
if (r < 0)
return r;
if (!saved_after)
saved_after = n;
- q = dns_label_unescape(&s, ls, sizeof(ls));
+ q = dns_label_unescape(&s, ls, sizeof ls, 0);
if (q < 0)
return q;
@@ -668,7 +687,7 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
/* Found it! Now generate the new name */
prefix = strndupa(name, saved_before - name);
- r = dns_name_concat(prefix, new_suffix, ret);
+ r = dns_name_concat(prefix, new_suffix, 0, ret);
if (r < 0)
return r;
@@ -746,7 +765,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
for (i = 0; i < ELEMENTSOF(a); i++) {
char label[DNS_LABEL_MAX+1];
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r < 0)
return r;
if (r == 0)
@@ -783,7 +802,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
char label[DNS_LABEL_MAX+1];
int x, y;
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r <= 0)
return r;
if (r != 1)
@@ -792,7 +811,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
if (x < 0)
return -EINVAL;
- r = dns_label_unescape(&p, label, sizeof(label));
+ r = dns_label_unescape(&p, label, sizeof label, 0);
if (r <= 0)
return r;
if (r != 1)
@@ -861,7 +880,7 @@ int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, boo
* dns_label_unescape() returns 0 when it hits the end
* of the domain name, which we rely on here to encode
* the trailing NUL byte. */
- r = dns_label_unescape(&domain, (char *) out, len);
+ r = dns_label_unescape(&domain, (char *) out, len, 0);
if (r < 0)
return r;
@@ -929,7 +948,7 @@ bool dns_srv_type_is_valid(const char *name) {
/* This more or less implements RFC 6335, Section 5.1 */
- r = dns_label_unescape(&name, label, sizeof(label));
+ r = dns_label_unescape(&name, label, sizeof label, 0);
if (r < 0)
return false;
if (r == 0)
@@ -989,7 +1008,7 @@ int dns_service_join(const char *name, const char *type, const char *domain, cha
return -EINVAL;
if (!name)
- return dns_name_concat(type, domain, ret);
+ return dns_name_concat(type, domain, 0, ret);
if (!dns_service_name_is_valid(name))
return -EINVAL;
@@ -998,11 +1017,11 @@ int dns_service_join(const char *name, const char *type, const char *domain, cha
if (r < 0)
return r;
- r = dns_name_concat(type, domain, &n);
+ r = dns_name_concat(type, domain, 0, &n);
if (r < 0)
return r;
- return dns_name_concat(escaped, n, ret);
+ return dns_name_concat(escaped, n, 0, ret);
}
static bool dns_service_name_label_is_valid(const char *label, size_t n) {
@@ -1027,7 +1046,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
assert(joined);
/* Get first label from the full name */
- an = dns_label_unescape(&p, a, sizeof(a));
+ an = dns_label_unescape(&p, a, sizeof(a), 0);
if (an < 0)
return an;
@@ -1035,7 +1054,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
x++;
/* If there was a first label, try to get the second one */
- bn = dns_label_unescape(&p, b, sizeof(b));
+ bn = dns_label_unescape(&p, b, sizeof(b), 0);
if (bn < 0)
return bn;
@@ -1044,7 +1063,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
/* If there was a second label, try to get the third one */
q = p;
- cn = dns_label_unescape(&p, c, sizeof(c));
+ cn = dns_label_unescape(&p, c, sizeof(c), 0);
if (cn < 0)
return cn;
@@ -1094,7 +1113,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
d = joined;
finish:
- r = dns_name_normalize(d, &domain);
+ r = dns_name_normalize(d, 0, &domain);
if (r < 0)
return r;
@@ -1110,7 +1129,7 @@ finish:
return 0;
}
-static int dns_name_build_suffix_table(const char *name, const char*table[]) {
+static int dns_name_build_suffix_table(const char *name, const char *table[]) {
const char *p;
unsigned n = 0;
int r;
@@ -1239,12 +1258,12 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
}
x = a_labels[n - 1 - k];
- r = dns_label_unescape(&x, la, sizeof(la));
+ r = dns_label_unescape(&x, la, sizeof la, 0);
if (r < 0)
return r;
y = b_labels[m - 1 - k];
- q = dns_label_unescape(&y, lb, sizeof(lb));
+ q = dns_label_unescape(&y, lb, sizeof lb, 0);
if (q < 0)
return q;
@@ -1312,13 +1331,13 @@ int dns_name_apply_idna(const char *name, char **ret) {
for (;;) {
char label[DNS_LABEL_MAX];
- r = dns_label_unescape(&name, label, sizeof(label));
+ r = dns_label_unescape(&name, label, sizeof label, 0);
if (r < 0)
return r;
if (r == 0)
break;
- q = dns_label_apply_idna(label, r, label, sizeof(label));
+ q = dns_label_apply_idna(label, r, label, sizeof label);
if (q < 0)
return q;
if (q > 0)
diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h
index 95f4069cc0..88b3eb112c 100644
--- a/src/systemd/src/shared/dns-domain.h
+++ b/src/systemd/src/shared/dns-domain.h
@@ -24,13 +24,18 @@
/* Maximum number of labels per valid hostname */
#define DNS_N_LABELS_MAX 127
-int dns_label_unescape(const char **name, char *dest, size_t sz);
+typedef enum DNSLabelFlags {
+ DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */
+ DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */
+} DNSLabelFlags;
+
+int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags);
int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
int dns_label_escape(const char *p, size_t l, char *dest, size_t sz);
int dns_label_escape_new(const char *p, size_t l, char **ret);
static inline int dns_name_parent(const char **name) {
- return dns_label_unescape(name, NULL, DNS_LABEL_MAX);
+ return dns_label_unescape(name, NULL, DNS_LABEL_MAX, 0);
}
#if 0 /* NM_IGNORED */
@@ -40,18 +45,29 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
#endif
#endif /* NM_IGNORED */
-int dns_name_concat(const char *a, const char *b, char **ret);
+int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret);
-static inline int dns_name_normalize(const char *s, char **ret) {
+static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char **ret) {
/* dns_name_concat() normalizes as a side-effect */
- return dns_name_concat(s, NULL, ret);
+ return dns_name_concat(s, NULL, flags, ret);
}
static inline int dns_name_is_valid(const char *s) {
int r;
/* dns_name_normalize() verifies as a side effect */
- r = dns_name_normalize(s, NULL);
+ r = dns_name_normalize(s, 0, NULL);
+ if (r == -EINVAL)
+ return 0;
+ if (r < 0)
+ return r;
+ return 1;
+}
+
+static inline int dns_name_is_valid_ldh(const char *s) {
+ int r;
+
+ r = dns_name_concat(s, NULL, DNS_LABEL_LDH|DNS_LABEL_NO_ESCAPES, NULL);
if (r == -EINVAL)
return 0;
if (r < 0)
@@ -59,8 +75,8 @@ static inline int dns_name_is_valid(const char *s) {
return 1;
}
-void dns_name_hash_func(const void *s, struct siphash *state);
-int dns_name_compare_func(const void *a, const void *b);
+void dns_name_hash_func(const char *s, struct siphash *state);
+int dns_name_compare_func(const char *a, const char *b);
extern const struct hash_ops dns_name_hash_ops;
int dns_name_between(const char *a, const char *b, const char *c);
diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h
index b026b5c551..05c38008cf 100644
--- a/src/systemd/src/systemd/_sd-common.h
+++ b/src/systemd/src/systemd/_sd-common.h
@@ -23,9 +23,11 @@
# error "Do not include _sd-common.h directly; it is a private header."
#endif
+typedef void (*_sd_destroy_t)(void *userdata);
+
#ifndef _sd_printf_
# if __GNUC__ >= 4
-# define _sd_printf_(a,b) __attribute__ ((__format__(printf, a, b)))
+# define _sd_printf_(a,b) __attribute__((__format__(printf, a, b)))
# else
# define _sd_printf_(a,b)
# endif
diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h
index e388552064..bd0d429df6 100644
--- a/src/systemd/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/src/systemd/sd-dhcp-client.h
@@ -23,6 +23,7 @@
#include <net/ethernet.h>
#include <netinet/in.h>
#include <sys/types.h>
+#include <stdbool.h>
#include "sd-dhcp-lease.h"
#include "sd-event.h"
@@ -127,12 +128,14 @@ int sd_dhcp_client_set_client_id(
size_t data_len);
int sd_dhcp_client_set_iaid_duid(
sd_dhcp_client *client,
+ bool iaid_set,
uint32_t iaid,
uint16_t duid_type,
const void *duid,
size_t duid_len);
int sd_dhcp_client_set_iaid_duid_llt(
sd_dhcp_client *client,
+ bool iaid_set,
uint32_t iaid,
uint64_t llt_time);
int sd_dhcp_client_set_duid(
diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h
index b15cade20a..787a12f241 100644
--- a/src/systemd/src/systemd/sd-event.h
+++ b/src/systemd/src/systemd/sd-event.h
@@ -77,7 +77,7 @@ typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si,
typedef void* sd_event_child_handler_t;
#endif
typedef int (*sd_event_inotify_handler_t)(sd_event_source *s, const struct inotify_event *event, void *userdata);
-typedef void (*sd_event_destroy_t)(void *userdata);
+typedef _sd_destroy_t sd_event_destroy_t;
int sd_event_default(sd_event **e);
diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h
index 78cf9462b0..f4c05a3683 100644
--- a/src/systemd/src/systemd/sd-id128.h
+++ b/src/systemd/src/systemd/sd-id128.h
@@ -41,19 +41,20 @@ int sd_id128_from_string(const char *s, sd_id128_t *ret);
int sd_id128_randomize(sd_id128_t *ret);
int sd_id128_get_machine(sd_id128_t *ret);
-int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret);
-int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
int sd_id128_get_boot(sd_id128_t *ret);
int sd_id128_get_invocation(sd_id128_t *ret);
-#define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \
- ((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \
- 0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }})
+int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret);
+int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
#define SD_ID128_ARRAY(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \
{ .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \
0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }}
+#define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \
+ ((const sd_id128_t) SD_ID128_ARRAY(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15))
+
+
/* Note that SD_ID128_FORMAT_VAL will evaluate the passed argument 16
* times. It is hence not a good idea to call this macro with an
* expensive function as parameter or an expression with side
@@ -109,7 +110,12 @@ _sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) {
return a.qwords[0] == 0 && a.qwords[1] == 0;
}
+_sd_pure_ static __inline__ int sd_id128_is_allf(sd_id128_t a) {
+ return a.qwords[0] == UINT64_C(0xFFFFFFFFFFFFFFFF) && a.qwords[1] == UINT64_C(0xFFFFFFFFFFFFFFFF);
+}
+
#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }})
+#define SD_ID128_ALLF ((const sd_id128_t) { .qwords = { UINT64_C(0xFFFFFFFFFFFFFFFF), UINT64_C(0xFFFFFFFFFFFFFFFF) }})
_SD_END_DECLARATIONS;