summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2017-08-09 14:30:44 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2017-08-09 14:30:44 +0200
commitdc1bfde56b9b354586603d740bc8ca7851f64a6d (patch)
tree369928379b33ca0846126828ed3c470f7fe1e7e1
parentcd5ef1ed7dbbd235f9cfe75c44fabe74e5b0300e (diff)
downloadNetworkManager-dc1bfde56b9b354586603d740bc8ca7851f64a6d.tar.gz
systemd: update code from upstream (2017-08-09)
This is a direct dump from systemd git on 2017-08-09, git commit c7f6ca9379279affa8f22d15fa13063491f86a49. ====== SYSTEMD_DIR=../systemd COMMIT=c7f6ca9379279affa8f22d15fa13063491f86a49 ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files :/src/systemd/src/ | xargs -d '\n' rm -f nm_copy_sd() { mkdir -p "./src/systemd/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/systemd/$1" } nm_copy_sd "src/basic/alloc-util.c" nm_copy_sd "src/basic/alloc-util.h" nm_copy_sd "src/basic/async.h" nm_copy_sd "src/basic/escape.c" nm_copy_sd "src/basic/escape.h" nm_copy_sd "src/basic/ether-addr-util.c" nm_copy_sd "src/basic/ether-addr-util.h" nm_copy_sd "src/basic/extract-word.c" nm_copy_sd "src/basic/extract-word.h" nm_copy_sd "src/basic/fileio.c" nm_copy_sd "src/basic/fileio.h" nm_copy_sd "src/basic/fd-util.c" nm_copy_sd "src/basic/fd-util.h" nm_copy_sd "src/basic/fs-util.c" nm_copy_sd "src/basic/fs-util.h" nm_copy_sd "src/basic/hash-funcs.c" nm_copy_sd "src/basic/hash-funcs.h" nm_copy_sd "src/basic/hashmap.c" nm_copy_sd "src/basic/hashmap.h" nm_copy_sd "src/basic/hexdecoct.c" nm_copy_sd "src/basic/hexdecoct.h" nm_copy_sd "src/basic/hostname-util.c" nm_copy_sd "src/basic/hostname-util.h" nm_copy_sd "src/basic/in-addr-util.c" nm_copy_sd "src/basic/in-addr-util.h" nm_copy_sd "src/basic/io-util.c" nm_copy_sd "src/basic/io-util.h" nm_copy_sd "src/basic/list.h" nm_copy_sd "src/basic/log.h" nm_copy_sd "src/basic/macro.h" nm_copy_sd "src/basic/mempool.h" nm_copy_sd "src/basic/mempool.c" nm_copy_sd "src/basic/parse-util.c" nm_copy_sd "src/basic/parse-util.h" nm_copy_sd "src/basic/path-util.c" nm_copy_sd "src/basic/path-util.h" nm_copy_sd "src/basic/prioq.h" nm_copy_sd "src/basic/prioq.c" nm_copy_sd "src/basic/process-util.h" nm_copy_sd "src/basic/process-util.c" nm_copy_sd "src/basic/random-util.c" nm_copy_sd "src/basic/random-util.h" nm_copy_sd "src/basic/refcnt.h" nm_copy_sd "src/basic/set.h" nm_copy_sd "src/basic/signal-util.h" nm_copy_sd "src/basic/siphash24.c" nm_copy_sd "src/basic/siphash24.h" nm_copy_sd "src/basic/socket-util.c" nm_copy_sd "src/basic/socket-util.h" nm_copy_sd "src/basic/sparse-endian.h" nm_copy_sd "src/basic/stdio-util.h" nm_copy_sd "src/basic/string-table.c" nm_copy_sd "src/basic/string-table.h" nm_copy_sd "src/basic/string-util.c" nm_copy_sd "src/basic/string-util.h" nm_copy_sd "src/basic/strv.c" nm_copy_sd "src/basic/strv.h" nm_copy_sd "src/basic/time-util.c" nm_copy_sd "src/basic/time-util.h" nm_copy_sd "src/basic/umask-util.h" nm_copy_sd "src/basic/unaligned.h" nm_copy_sd "src/basic/utf8.c" nm_copy_sd "src/basic/utf8.h" nm_copy_sd "src/basic/util.c" nm_copy_sd "src/basic/util.h" nm_copy_sd "src/libsystemd-network/arp-util.c" nm_copy_sd "src/libsystemd-network/arp-util.h" nm_copy_sd "src/libsystemd-network/dhcp6-internal.h" nm_copy_sd "src/libsystemd-network/dhcp6-lease-internal.h" nm_copy_sd "src/libsystemd-network/dhcp6-network.c" nm_copy_sd "src/libsystemd-network/dhcp6-option.c" nm_copy_sd "src/libsystemd-network/dhcp6-protocol.h" nm_copy_sd "src/libsystemd-network/dhcp-identifier.c" nm_copy_sd "src/libsystemd-network/dhcp-identifier.h" nm_copy_sd "src/libsystemd-network/dhcp-internal.h" nm_copy_sd "src/libsystemd-network/dhcp-lease-internal.h" nm_copy_sd "src/libsystemd-network/dhcp-network.c" nm_copy_sd "src/libsystemd-network/dhcp-option.c" nm_copy_sd "src/libsystemd-network/dhcp-packet.c" nm_copy_sd "src/libsystemd-network/dhcp-protocol.h" nm_copy_sd "src/libsystemd-network/lldp-internal.h" nm_copy_sd "src/libsystemd-network/lldp-neighbor.c" nm_copy_sd "src/libsystemd-network/lldp-neighbor.h" nm_copy_sd "src/libsystemd-network/lldp-network.c" nm_copy_sd "src/libsystemd-network/lldp-network.h" nm_copy_sd "src/libsystemd-network/network-internal.c" nm_copy_sd "src/libsystemd-network/network-internal.h" nm_copy_sd "src/libsystemd-network/sd-dhcp6-client.c" nm_copy_sd "src/libsystemd-network/sd-dhcp6-lease.c" nm_copy_sd "src/libsystemd-network/sd-dhcp-client.c" nm_copy_sd "src/libsystemd-network/sd-dhcp-lease.c" nm_copy_sd "src/libsystemd-network/sd-ipv4ll.c" nm_copy_sd "src/libsystemd-network/sd-ipv4acd.c" nm_copy_sd "src/libsystemd-network/sd-lldp.c" nm_copy_sd "src/libsystemd/sd-event/sd-event.c" nm_copy_sd "src/libsystemd/sd-id128/id128-util.c" nm_copy_sd "src/libsystemd/sd-id128/id128-util.h" nm_copy_sd "src/libsystemd/sd-id128/sd-id128.c" nm_copy_sd "src/shared/dns-domain.c" nm_copy_sd "src/shared/dns-domain.h" nm_copy_sd "src/systemd/_sd-common.h" nm_copy_sd "src/systemd/sd-dhcp6-client.h" nm_copy_sd "src/systemd/sd-dhcp6-lease.h" nm_copy_sd "src/systemd/sd-dhcp-client.h" nm_copy_sd "src/systemd/sd-dhcp-lease.h" nm_copy_sd "src/systemd/sd-event.h" nm_copy_sd "src/systemd/sd-ndisc.h" nm_copy_sd "src/systemd/sd-id128.h" nm_copy_sd "src/systemd/sd-ipv4acd.h" nm_copy_sd "src/systemd/sd-ipv4ll.h" nm_copy_sd "src/systemd/sd-lldp.h"
-rw-r--r--src/systemd/src/basic/alloc-util.c27
-rw-r--r--src/systemd/src/basic/alloc-util.h10
-rw-r--r--src/systemd/src/basic/escape.c40
-rw-r--r--src/systemd/src/basic/escape.h23
-rw-r--r--src/systemd/src/basic/fd-util.c3
-rw-r--r--src/systemd/src/basic/fileio.c21
-rw-r--r--src/systemd/src/basic/fs-util.c2
-rw-r--r--src/systemd/src/basic/hexdecoct.c3
-rw-r--r--src/systemd/src/basic/hostname-util.c7
-rw-r--r--src/systemd/src/basic/log.h10
-rw-r--r--src/systemd/src/basic/parse-util.c17
-rw-r--r--src/systemd/src/basic/parse-util.h1
-rw-r--r--src/systemd/src/basic/path-util.c4
-rw-r--r--src/systemd/src/basic/path-util.h2
-rw-r--r--src/systemd/src/basic/process-util.c1043
-rw-r--r--src/systemd/src/basic/process-util.h127
-rw-r--r--src/systemd/src/basic/random-util.c120
-rw-r--r--src/systemd/src/basic/random-util.h4
-rw-r--r--src/systemd/src/basic/socket-util.c11
-rw-r--r--src/systemd/src/basic/socket-util.h20
-rw-r--r--src/systemd/src/basic/string-util.c27
-rw-r--r--src/systemd/src/basic/string-util.h9
-rw-r--r--src/systemd/src/basic/strv.c6
-rw-r--r--src/systemd/src/basic/time-util.c47
-rw-r--r--src/systemd/src/basic/time-util.h17
-rw-r--r--src/systemd/src/basic/util.c4
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-network.c16
-rw-r--r--src/systemd/src/libsystemd-network/lldp-neighbor.c7
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-lease.c12
-rw-r--r--src/systemd/src/libsystemd/sd-event/sd-event.c4
-rw-r--r--src/systemd/src/libsystemd/sd-id128/sd-id128.c2
-rw-r--r--src/systemd/src/shared/dns-domain.c40
32 files changed, 1538 insertions, 148 deletions
diff --git a/src/systemd/src/basic/alloc-util.c b/src/systemd/src/basic/alloc-util.c
index b540dcddf5..948389f276 100644
--- a/src/systemd/src/basic/alloc-util.c
+++ b/src/systemd/src/basic/alloc-util.c
@@ -25,16 +25,31 @@
#include "util.h"
void* memdup(const void *p, size_t l) {
- void *r;
+ void *ret;
- assert(p);
+ assert(l == 0 || p);
+
+ ret = malloc(l);
+ if (!ret)
+ return NULL;
+
+ memcpy(ret, p, l);
+ return ret;
+}
+
+void* memdup_suffix0(const void*p, size_t l) {
+ void *ret;
+
+ assert(l == 0 || p);
+
+ /* The same as memdup() but place a safety NUL byte after the allocated memory */
- r = malloc(l);
- if (!r)
+ ret = malloc(l + 1);
+ if (!ret)
return NULL;
- memcpy(r, p, l);
- return r;
+ *((uint8_t*) mempcpy(ret, p, l)) = 0;
+ return ret;
}
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
diff --git a/src/systemd/src/basic/alloc-util.h b/src/systemd/src/basic/alloc-util.h
index a44dd473c1..0a89691bae 100644
--- a/src/systemd/src/basic/alloc-util.h
+++ b/src/systemd/src/basic/alloc-util.h
@@ -36,6 +36,8 @@
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
+#define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
+
#define malloc0(n) (calloc(1, (n)))
static inline void *mfree(void *memory) {
@@ -52,6 +54,7 @@ static inline void *mfree(void *memory) {
})
void* memdup(const void *p, size_t l) _alloc_(2);
+void* memdup_suffix0(const void*p, size_t l) _alloc_(2);
static inline void freep(void *p) {
free(*(void**) p);
@@ -84,6 +87,13 @@ _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, si
return memdup(p, size * need);
}
+_alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
+ if (size_multiply_overflow(size, need))
+ return NULL;
+
+ return memdup_suffix0(p, size * need);
+}
+
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
diff --git a/src/systemd/src/basic/escape.c b/src/systemd/src/basic/escape.c
index 4a1ec4505e..22b8b04156 100644
--- a/src/systemd/src/basic/escape.c
+++ b/src/systemd/src/basic/escape.c
@@ -314,7 +314,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
/* Undoes C style string escaping, and optionally prefixes it. */
- pl = prefix ? strlen(prefix) : 0;
+ pl = strlen_ptr(prefix);
r = new(char, pl+length+1);
if (!r)
@@ -441,10 +441,16 @@ char *octescape(const char *s, size_t len) {
}
-static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
+static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad, bool escape_tab_nl) {
assert(bad);
for (; *s; s++) {
+ if (escape_tab_nl && IN_SET(*s, '\n', '\t')) {
+ *(t++) = '\\';
+ *(t++) = *s == '\n' ? 'n' : 't';
+ continue;
+ }
+
if (*s == '\\' || strchr(bad, *s))
*(t++) = '\\';
@@ -461,20 +467,21 @@ char *shell_escape(const char *s, const char *bad) {
if (!r)
return NULL;
- t = strcpy_backslash_escaped(r, s, bad);
+ t = strcpy_backslash_escaped(r, s, bad, false);
*t = 0;
return r;
}
-char *shell_maybe_quote(const char *s) {
+char* shell_maybe_quote(const char *s, EscapeStyle style) {
const char *p;
char *r, *t;
assert(s);
- /* Encloses a string in double quotes if necessary to make it
- * OK as shell string. */
+ /* Encloses a string in quotes if necessary to make it OK as a shell
+ * string. Note that we treat benign UTF-8 characters as needing
+ * escaping too, but that should be OK. */
for (p = s; *p; p++)
if (*p <= ' ' ||
@@ -485,17 +492,30 @@ char *shell_maybe_quote(const char *s) {
if (!*p)
return strdup(s);
- r = new(char, 1+strlen(s)*2+1+1);
+ r = new(char, (style == ESCAPE_POSIX) + 1 + strlen(s)*2 + 1 + 1);
if (!r)
return NULL;
t = r;
- *(t++) = '"';
+ if (style == ESCAPE_BACKSLASH)
+ *(t++) = '"';
+ else if (style == ESCAPE_POSIX) {
+ *(t++) = '$';
+ *(t++) = '\'';
+ } else
+ assert_not_reached("Bad EscapeStyle");
+
t = mempcpy(t, s, p - s);
- t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
+ if (style == ESCAPE_BACKSLASH)
+ t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE, false);
+ else
+ t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE_POSIX, true);
- *(t++)= '"';
+ if (style == ESCAPE_BACKSLASH)
+ *(t++) = '"';
+ else
+ *(t++) = '\'';
*t = 0;
return r;
diff --git a/src/systemd/src/basic/escape.h b/src/systemd/src/basic/escape.h
index deaa4def28..6f5cc60bc8 100644
--- a/src/systemd/src/basic/escape.h
+++ b/src/systemd/src/basic/escape.h
@@ -31,13 +31,30 @@
/* What characters are special in the shell? */
/* must be escaped outside and inside double-quotes */
#define SHELL_NEED_ESCAPE "\"\\`$"
-/* can be escaped or double-quoted */
-#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;"
+
+/* Those that can be escaped or double-quoted.
+ *
+ * Stricly speaking, ! does not need to be escaped, except in interactive
+ * mode, but let's be extra nice to the user and quote ! in case this
+ * output is ever used in interactive mode. */
+#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;!"
+
+/* Note that we assume control characters would need to be escaped too in
+ * addition to the "special" characters listed here, if they appear in the
+ * string. Current users disallow control characters. Also '"' shall not
+ * be escaped.
+ */
+#define SHELL_NEED_ESCAPE_POSIX "\\\'"
typedef enum UnescapeFlags {
UNESCAPE_RELAX = 1,
} UnescapeFlags;
+typedef enum EscapeStyle {
+ ESCAPE_BACKSLASH = 1,
+ ESCAPE_POSIX = 2,
+} EscapeStyle;
+
char *cescape(const char *s);
char *cescape_length(const char *s, size_t n);
size_t cescape_char(char c, char *buf);
@@ -51,4 +68,4 @@ char *xescape(const char *s, const char *bad);
char *octescape(const char *s, size_t len);
char *shell_escape(const char *s, const char *bad);
-char *shell_maybe_quote(const char *s);
+char* shell_maybe_quote(const char *s, EscapeStyle style);
diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c
index 19ad20789b..9d61044c89 100644
--- a/src/systemd/src/basic/fd-util.c
+++ b/src/systemd/src/basic/fd-util.c
@@ -31,6 +31,7 @@
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "util.h"
@@ -282,7 +283,7 @@ int same_fd(int a, int b) {
return true;
/* Try to use kcmp() if we have it. */
- pid = getpid();
+ pid = getpid_cached();
r = kcmp(pid, pid, KCMP_FILE, a, b);
if (r == 0)
return true;
diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c
index 9a185e3e60..a025038588 100644
--- a/src/systemd/src/basic/fileio.c
+++ b/src/systemd/src/basic/fileio.c
@@ -41,6 +41,7 @@
#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"
@@ -823,29 +824,29 @@ static void write_env_var(FILE *f, const char *v) {
p = strchr(v, '=');
if (!p) {
/* Fallback */
- fputs(v, f);
- fputc('\n', f);
+ fputs_unlocked(v, f);
+ fputc_unlocked('\n', f);
return;
}
p++;
- fwrite(v, 1, p-v, f);
+ fwrite_unlocked(v, 1, p-v, f);
if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
- fputc('\"', f);
+ fputc_unlocked('\"', f);
for (; *p; p++) {
if (strchr(SHELL_NEED_ESCAPE, *p))
- fputc('\\', f);
+ fputc_unlocked('\\', f);
- fputc(*p, f);
+ fputc_unlocked(*p, f);
}
- fputc('\"', f);
+ fputc_unlocked('\"', f);
} else
- fputs(p, f);
+ fputs_unlocked(p, f);
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
int write_env_file(const char *fname, char **l) {
@@ -1399,7 +1400,7 @@ int open_serialization_fd(const char *ident) {
if (fd < 0) {
const char *path;
- path = getpid() == 1 ? "/run/systemd" : "/tmp";
+ path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
if (fd < 0)
return fd;
diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c
index 8fe19ee4e4..5e1163c6a7 100644
--- a/src/systemd/src/basic/fs-util.c
+++ b/src/systemd/src/basic/fs-util.c
@@ -307,7 +307,7 @@ int fd_warn_permissions(const char *path, int fd) {
if (st.st_mode & 0002)
log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
- if (getpid() == 1 && (st.st_mode & 0044) != 0044)
+ if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044)
log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
return 0;
diff --git a/src/systemd/src/basic/hexdecoct.c b/src/systemd/src/basic/hexdecoct.c
index 2d6e377f0a..766770389c 100644
--- a/src/systemd/src/basic/hexdecoct.c
+++ b/src/systemd/src/basic/hexdecoct.c
@@ -25,6 +25,7 @@
#include "alloc-util.h"
#include "hexdecoct.h"
#include "macro.h"
+#include "string-util.h"
#include "util.h"
char octchar(int x) {
@@ -569,7 +570,7 @@ static int base64_append_width(char **prefix, int plen,
lines = (len + width - 1) / width;
- slen = sep ? strlen(sep) : 0;
+ slen = strlen_ptr(sep);
t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
if (!t)
return -ENOMEM;
diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c
index a94037b303..b511a36301 100644
--- a/src/systemd/src/basic/hostname-util.c
+++ b/src/systemd/src/basic/hostname-util.c
@@ -196,8 +196,11 @@ bool is_gateway_hostname(const char *hostname) {
* synthetic "gateway" host. */
return
- strcaseeq(hostname, "gateway") ||
- strcaseeq(hostname, "gateway.");
+ strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.")
+#if ENABLE_COMPAT_GATEWAY_HOSTNAME
+ || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.")
+#endif
+ ;
}
int sethostname_idempotent(const char *s) {
diff --git a/src/systemd/src/basic/log.h b/src/systemd/src/basic/log.h
index 57463fbb83..186747ff8e 100644
--- a/src/systemd/src/basic/log.h
+++ b/src/systemd/src/basic/log.h
@@ -30,6 +30,7 @@
#include "sd-id128.h"
#include "macro.h"
+#include "process-util.h"
typedef enum LogRealm {
LOG_REALM_SYSTEMD,
@@ -86,6 +87,11 @@ int log_get_max_level_realm(LogRealm realm) _pure_;
#define log_get_max_level() \
log_get_max_level_realm(LOG_REALM)
+/* Functions below that open and close logs or configure logging based on the
+ * environment should not be called from library code — this is always a job
+ * for the application itself.
+ */
+
int log_open(void);
void log_close(void);
void log_forget_fds(void);
@@ -242,7 +248,7 @@ void log_assert_failed_return_realm(
#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__)
#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__)
#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
-#define log_emergency(...) log_full(getpid() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
+#define log_emergency(...) log_full(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
/* Logging triggered by an errno-like error */
#define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__)
@@ -250,7 +256,7 @@ void log_assert_failed_return_realm(
#define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__)
#define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__)
#define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__)
-#define log_emergency_errno(error, ...) log_full_errno(getpid() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
+#define log_emergency_errno(error, ...) log_full_errno(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
#ifdef LOG_TRACE
# define log_trace(...) log_debug(__VA_ARGS__)
diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c
index d86700736d..89bb667c5f 100644
--- a/src/systemd/src/basic/parse-util.c
+++ b/src/systemd/src/basic/parse-util.c
@@ -59,7 +59,7 @@ int parse_pid(const char *s, pid_t* ret_pid) {
if ((unsigned long) pid != ul)
return -ERANGE;
- if (pid <= 0)
+ if (!pid_is_valid(pid))
return -ERANGE;
*ret_pid = pid;
@@ -589,3 +589,18 @@ int parse_ip_port(const char *s, uint16_t *ret) {
return 0;
}
+
+int parse_dev(const char *s, dev_t *ret) {
+ unsigned x, y;
+ dev_t d;
+
+ if (sscanf(s, "%u:%u", &x, &y) != 2)
+ return -EINVAL;
+
+ d = makedev(x, y);
+ if ((unsigned) major(d) != x || (unsigned) minor(d) != y)
+ return -EINVAL;
+
+ *ret = d;
+ return 0;
+}
diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h
index 4d132f0de5..dc09782ca8 100644
--- a/src/systemd/src/basic/parse-util.h
+++ b/src/systemd/src/basic/parse-util.h
@@ -30,6 +30,7 @@
#define MODE_INVALID ((mode_t) -1)
int parse_boolean(const char *v) _pure_;
+int parse_dev(const char *s, dev_t *ret);
int parse_pid(const char *s, pid_t* ret_pid);
int parse_mode(const char *s, mode_t *ret);
int parse_ifindex(const char *s, int *ret);
diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c
index 1313a52c9c..80fdda170f 100644
--- a/src/systemd/src/basic/path-util.c
+++ b/src/systemd/src/basic/path-util.c
@@ -442,8 +442,8 @@ bool path_equal(const char *a, const char *b) {
return path_compare(a, b) == 0;
}
-bool path_equal_or_files_same(const char *a, const char *b) {
- return path_equal(a, b) || files_same(a, b) > 0;
+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) {
diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h
index 35aef3adc8..26f165fc38 100644
--- a/src/systemd/src/basic/path-util.h
+++ b/src/systemd/src/basic/path-util.h
@@ -46,7 +46,7 @@ char* path_kill_slashes(char *path);
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);
+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);
static inline bool path_equal_ptr(const char *a, const char *b) {
diff --git a/src/systemd/src/basic/process-util.c b/src/systemd/src/basic/process-util.c
new file mode 100644
index 0000000000..2b23ac36c0
--- /dev/null
+++ b/src/systemd/src/basic/process-util.c
@@ -0,0 +1,1043 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <linux/oom.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/personality.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <syslog.h>
+#include <unistd.h>
+#ifdef HAVE_VALGRIND_VALGRIND_H
+#include <valgrind/valgrind.h>
+#endif
+
+#include "alloc-util.h"
+#include "architecture.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "ioprio.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "process-util.h"
+#include "raw-clone.h"
+#include "signal-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
+
+int get_process_state(pid_t pid) {
+ const char *p;
+ char state;
+ int r;
+ _cleanup_free_ char *line = NULL;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "stat");
+
+ r = read_one_line_file(p, &line);
+ if (r == -ENOENT)
+ return -ESRCH;
+ if (r < 0)
+ return r;
+
+ p = strrchr(line, ')');
+ if (!p)
+ return -EIO;
+
+ p++;
+
+ if (sscanf(p, " %c", &state) != 1)
+ return -EIO;
+
+ return (unsigned char) state;
+}
+
+int get_process_comm(pid_t pid, char **name) {
+ const char *p;
+ int r;
+
+ assert(name);
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "comm");
+
+ r = read_one_line_file(p, name);
+ if (r == -ENOENT)
+ return -ESRCH;
+
+ return r;
+}
+
+int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
+ _cleanup_fclose_ FILE *f = NULL;
+ bool space = false;
+ char *k, *ans = NULL;
+ const char *p;
+ int c;
+
+ assert(line);
+ assert(pid >= 0);
+
+ /* Retrieves a process' command line. Replaces unprintable characters while doing so by whitespace (coalescing
+ * multiple sequential ones into one). If max_length is != 0 will return a string of the specified size at most
+ * (the trailing NUL byte does count towards the length here!), abbreviated with a "..." ellipsis. If
+ * comm_fallback is true and the process has no command line set (the case for kernel threads), or has a
+ * command line that resolves to the empty string will return the "comm" name of the process instead.
+ *
+ * Returns -ESRCH if the process doesn't exist, and -ENOENT if the process has no command line (and
+ * comm_fallback is false). Returns 0 and sets *line otherwise. */
+
+ p = procfs_file_alloca(pid, "cmdline");
+
+ f = fopen(p, "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
+ return -errno;
+ }
+
+ if (max_length == 1) {
+
+ /* If there's only room for one byte, return the empty string */
+ ans = new0(char, 1);
+ if (!ans)
+ return -ENOMEM;
+
+ *line = ans;
+ return 0;
+
+ } else if (max_length == 0) {
+ size_t len = 0, allocated = 0;
+
+ while ((c = getc(f)) != EOF) {
+
+ if (!GREEDY_REALLOC(ans, allocated, len+3)) {
+ free(ans);
+ return -ENOMEM;
+ }
+
+ if (isprint(c)) {
+ if (space) {
+ ans[len++] = ' ';
+ space = false;
+ }
+
+ ans[len++] = c;
+ } else if (len > 0)
+ space = true;
+ }
+
+ if (len > 0)
+ ans[len] = '\0';
+ else
+ ans = mfree(ans);
+
+ } else {
+ bool dotdotdot = false;
+ size_t left;
+
+ ans = new(char, max_length);
+ if (!ans)
+ return -ENOMEM;
+
+ k = ans;
+ left = max_length;
+ while ((c = getc(f)) != EOF) {
+
+ if (isprint(c)) {
+
+ if (space) {
+ if (left <= 2) {
+ dotdotdot = true;
+ break;
+ }
+
+ *(k++) = ' ';
+ left--;
+ space = false;
+ }
+
+ if (left <= 1) {
+ dotdotdot = true;
+ break;
+ }
+
+ *(k++) = (char) c;
+ left--;
+ } else if (k > ans)
+ space = true;
+ }
+
+ if (dotdotdot) {
+ if (max_length <= 4) {
+ k = ans;
+ left = max_length;
+ } else {
+ k = ans + max_length - 4;
+ left = 4;
+
+ /* Eat up final spaces */
+ while (k > ans && isspace(k[-1])) {
+ k--;
+ left++;
+ }
+ }
+
+ strncpy(k, "...", left-1);
+ k[left-1] = 0;
+ } else
+ *k = 0;
+ }
+
+ /* Kernel threads have no argv[] */
+ if (isempty(ans)) {
+ _cleanup_free_ char *t = NULL;
+ int h;
+
+ free(ans);
+
+ if (!comm_fallback)
+ return -ENOENT;
+
+ h = get_process_comm(pid, &t);
+ if (h < 0)
+ return h;
+
+ if (max_length == 0)
+ ans = strjoin("[", t, "]");
+ else {
+ size_t l;
+
+ l = strlen(t);
+
+ if (l + 3 <= max_length)
+ ans = strjoin("[", t, "]");
+ else if (max_length <= 6) {
+
+ ans = new(char, max_length);
+ if (!ans)
+ return -ENOMEM;
+
+ memcpy(ans, "[...]", max_length-1);
+ ans[max_length-1] = 0;
+ } else {
+ char *e;
+
+ t[max_length - 6] = 0;
+
+ /* Chop off final spaces */
+ e = strchr(t, 0);
+ while (e > t && isspace(e[-1]))
+ e--;
+ *e = 0;
+
+ ans = strjoin("[", t, "...]");
+ }
+ }
+ if (!ans)
+ return -ENOMEM;
+ }
+
+ *line = ans;
+ return 0;
+}
+
+int rename_process(const char name[]) {
+ static size_t mm_size = 0;
+ static char *mm = NULL;
+ bool truncated = false;
+ size_t l;
+
+ /* This is a like a poor man's setproctitle(). It changes the comm field, argv[0], and also the glibc's
+ * internally used name of the process. For the first one a limit of 16 chars applies; to the second one in
+ * many cases one of 10 (i.e. length of "/sbin/init") — however if we have CAP_SYS_RESOURCES it is unbounded;
+ * to the third one 7 (i.e. the length of "systemd". If you pass a longer string it will likely be
+ * truncated.
+ *
+ * Returns 0 if a name was set but truncated, > 0 if it was set but not truncated. */
+
+ if (isempty(name))
+ return -EINVAL; /* let's not confuse users unnecessarily with an empty name */
+
+ l = strlen(name);
+
+ /* First step, change the comm field. */
+ (void) prctl(PR_SET_NAME, name);
+ if (l > 15) /* Linux process names can be 15 chars at max */
+ truncated = true;
+
+ /* Second step, change glibc's ID of the process name. */
+ if (program_invocation_name) {
+ size_t k;
+
+ k = strlen(program_invocation_name);
+ strncpy(program_invocation_name, name, k);
+ if (l > k)
+ truncated = true;
+ }
+
+ /* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but
+ * has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at
+ * the end. This is the best option for changing /proc/self/cmdline. */
+
+ /* Let's not bother with this if we don't have euid == 0. Strictly speaking we should check for the
+ * CAP_SYS_RESOURCE capability which is independent of the euid. In our own code the capability generally is
+ * present only for euid == 0, hence let's use this as quick bypass check, to avoid calling mmap() if
+ * PR_SET_MM_ARG_{START,END} fails with EPERM later on anyway. After all geteuid() is dead cheap to call, but
+ * mmap() is not. */
+ if (geteuid() != 0)
+ log_debug("Skipping PR_SET_MM, as we don't have privileges.");
+ else if (mm_size < l+1) {
+ size_t nn_size;
+ char *nn;
+
+ nn_size = PAGE_ALIGN(l+1);
+ nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ if (nn == MAP_FAILED) {
+ log_debug_errno(errno, "mmap() failed: %m");
+ goto use_saved_argv;
+ }
+
+ strncpy(nn, name, nn_size);
+
+ /* Now, let's tell the kernel about this new memory */
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
+ log_debug_errno(errno, "PR_SET_MM_ARG_START failed, proceeding without: %m");
+ (void) munmap(nn, nn_size);
+ goto use_saved_argv;
+ }
+
+ /* And update the end pointer to the new end, too. If this fails, we don't really know what to do, it's
+ * pretty unlikely that we can rollback, hence we'll just accept the failure, and continue. */
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
+ log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+
+ if (mm)
+ (void) munmap(mm, mm_size);
+
+ mm = nn;
+ mm_size = nn_size;
+ } else {
+ strncpy(mm, name, mm_size);
+
+ /* Update the end pointer, continuing regardless of any failure. */
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0) < 0)
+ log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+ }
+
+use_saved_argv:
+ /* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if
+ * it still looks here */
+
+ if (saved_argc > 0) {
+ int i;
+
+ if (saved_argv[0]) {
+ size_t k;
+
+ k = strlen(saved_argv[0]);
+ strncpy(saved_argv[0], name, k);
+ if (l > k)
+ truncated = true;
+ }
+
+ for (i = 1; i < saved_argc; i++) {
+ if (!saved_argv[i])
+ break;
+
+ memzero(saved_argv[i], strlen(saved_argv[i]));
+ }
+ }
+
+ return !truncated;
+}
+
+int is_kernel_thread(pid_t pid) {
+ const char *p;
+ size_t count;
+ char c;
+ bool eof;
+ FILE *f;
+
+ if (pid == 0 || pid == 1 || pid == getpid_cached()) /* pid 1, and we ourselves certainly aren't a kernel thread */
+ return 0;
+
+ assert(pid > 1);
+
+ p = procfs_file_alloca(pid, "cmdline");
+ f = fopen(p, "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
+ return -errno;
+ }
+
+ count = fread(&c, 1, 1, f);
+ eof = feof(f);
+ fclose(f);
+
+ /* Kernel threads have an empty cmdline */
+
+ if (count <= 0)
+ return eof ? 1 : -errno;
+
+ return 0;
+}
+
+int get_process_capeff(pid_t pid, char **capeff) {
+ const char *p;
+ int r;
+
+ assert(capeff);
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "status");
+
+ r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
+ if (r == -ENOENT)
+ return -ESRCH;
+
+ return r;
+}
+
+static int get_process_link_contents(const char *proc_file, char **name) {
+ int r;
+
+ assert(proc_file);
+ assert(name);
+
+ r = readlink_malloc(proc_file, name);
+ if (r == -ENOENT)
+ return -ESRCH;
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int get_process_exe(pid_t pid, char **name) {
+ const char *p;
+ char *d;
+ int r;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "exe");
+ r = get_process_link_contents(p, name);
+ if (r < 0)
+ return r;
+
+ d = endswith(*name, " (deleted)");
+ if (d)
+ *d = '\0';
+
+ return 0;
+}
+
+static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char line[LINE_MAX];
+ const char *p;
+
+ assert(field);
+ assert(uid);
+
+ if (pid < 0)
+ return -EINVAL;
+
+ p = procfs_file_alloca(pid, "status");
+ f = fopen(p, "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
+ return -errno;
+ }
+
+ FOREACH_LINE(line, f, return -errno) {
+ char *l;
+
+ l = strstrip(line);
+
+ if (startswith(l, field)) {
+ l += strlen(field);
+ l += strspn(l, WHITESPACE);
+
+ l[strcspn(l, WHITESPACE)] = 0;
+
+ return parse_uid(l, uid);
+ }
+ }
+
+ return -EIO;
+}
+
+int get_process_uid(pid_t pid, uid_t *uid) {
+
+ if (pid == 0 || pid == getpid_cached()) {
+ *uid = getuid();
+ return 0;
+ }
+
+ return get_process_id(pid, "Uid:", uid);
+}
+
+int get_process_gid(pid_t pid, gid_t *gid) {
+
+ if (pid == 0 || pid == getpid_cached()) {
+ *gid = getgid();
+ return 0;
+ }
+
+ assert_cc(sizeof(uid_t) == sizeof(gid_t));
+ return get_process_id(pid, "Gid:", gid);
+}
+
+int get_process_cwd(pid_t pid, char **cwd) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "cwd");
+
+ return get_process_link_contents(p, cwd);
+}
+
+int get_process_root(pid_t pid, char **root) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "root");
+
+ return get_process_link_contents(p, root);
+}
+
+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;
+
+ assert(pid >= 0);
+ assert(env);
+
+ p = procfs_file_alloca(pid, "environ");
+
+ f = fopen(p, "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
+ return -errno;
+ }
+
+ while ((c = fgetc(f)) != EOF) {
+ if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
+ return -ENOMEM;
+
+ 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';
+
+ *env = outcome;
+ outcome = NULL;
+
+ return 0;
+}
+
+int get_process_ppid(pid_t pid, pid_t *_ppid) {
+ int r;
+ _cleanup_free_ char *line = NULL;
+ long unsigned ppid;
+ const char *p;
+
+ assert(pid >= 0);
+ assert(_ppid);
+
+ if (pid == 0 || pid == getpid_cached()) {
+ *_ppid = getppid();
+ return 0;
+ }
+
+ p = procfs_file_alloca(pid, "stat");
+ r = read_one_line_file(p, &line);
+ if (r == -ENOENT)
+ return -ESRCH;
+ if (r < 0)
+ return r;
+
+ /* Let's skip the pid and comm fields. The latter is enclosed
+ * in () but does not escape any () in its value, so let's
+ * skip over it manually */
+
+ p = strrchr(line, ')');
+ if (!p)
+ return -EIO;
+
+ p++;
+
+ if (sscanf(p, " "
+ "%*c " /* state */
+ "%lu ", /* ppid */
+ &ppid) != 1)
+ return -EIO;
+
+ if ((long unsigned) (pid_t) ppid != ppid)
+ return -ERANGE;
+
+ *_ppid = (pid_t) ppid;
+
+ return 0;
+}
+
+int wait_for_terminate(pid_t pid, siginfo_t *status) {
+ siginfo_t dummy;
+
+ assert(pid >= 1);
+
+ if (!status)
+ status = &dummy;
+
+ for (;;) {
+ zero(*status);
+
+ if (waitid(P_PID, pid, status, WEXITED) < 0) {
+
+ if (errno == EINTR)
+ continue;
+
+ return negative_errno();
+ }
+
+ return 0;
+ }
+}
+
+/*
+ * Return values:
+ * < 0 : wait_for_terminate() failed to get the state of the
+ * process, the process was terminated by a signal, or
+ * failed for an unknown reason.
+ * >=0 : The process terminated normally, and its exit code is
+ * returned.
+ *
+ * That is, success is indicated by a return value of zero, and an
+ * error is indicated by a non-zero value.
+ *
+ * A warning is emitted if the process terminates abnormally,
+ * and also if it returns non-zero unless check_exit_code is true.
+ */
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
+ int r;
+ siginfo_t status;
+
+ assert(name);
+ assert(pid > 1);
+
+ r = wait_for_terminate(pid, &status);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to wait for %s: %m", name);
+
+ if (status.si_code == CLD_EXITED) {
+ if (status.si_status != 0)
+ log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
+ "%s failed with error code %i.", name, status.si_status);
+ else
+ log_debug("%s succeeded.", name);
+
+ return status.si_status;
+ } else if (status.si_code == CLD_KILLED ||
+ status.si_code == CLD_DUMPED) {
+
+ log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
+ return -EPROTO;
+ }
+
+ log_warning("%s failed due to unknown reason.", name);
+ return -EPROTO;
+}
+
+void sigkill_wait(pid_t pid) {
+ assert(pid > 1);
+
+ if (kill(pid, SIGKILL) > 0)
+ (void) wait_for_terminate(pid, NULL);
+}
+
+void sigkill_waitp(pid_t *pid) {
+ if (!pid)
+ return;
+ if (*pid <= 1)
+ return;
+
+ sigkill_wait(*pid);
+}
+
+int kill_and_sigcont(pid_t pid, int sig) {
+ int r;
+
+ r = kill(pid, sig) < 0 ? -errno : 0;
+
+ /* If this worked, also send SIGCONT, unless we already just sent a SIGCONT, or SIGKILL was sent which isn't
+ * affected by a process being suspended anyway. */
+ if (r >= 0 && !IN_SET(sig, SIGCONT, SIGKILL))
+ (void) kill(pid, SIGCONT);
+
+ return r;
+}
+
+int getenv_for_pid(pid_t pid, const char *field, char **_value) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char *value = NULL;
+ int r;
+ bool done = false;
+ size_t l;
+ const char *path;
+
+ assert(pid >= 0);
+ assert(field);
+ assert(_value);
+
+ path = procfs_file_alloca(pid, "environ");
+
+ f = fopen(path, "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
+ return -errno;
+ }
+
+ l = strlen(field);
+ r = 0;
+
+ do {
+ char line[LINE_MAX];
+ unsigned i;
+
+ for (i = 0; i < sizeof(line)-1; i++) {
+ int c;
+
+ c = getc(f);
+ if (_unlikely_(c == EOF)) {
+ done = true;
+ break;
+ } else if (c == 0)
+ break;
+
+ line[i] = c;
+ }
+ line[i] = 0;
+
+ if (strneq(line, field, l) && line[l] == '=') {
+ value = strdup(line + l + 1);
+ if (!value)
+ return -ENOMEM;
+
+ r = 1;
+ break;
+ }
+
+ } while (!done);
+
+ *_value = value;
+ return r;
+}
+
+bool pid_is_unwaited(pid_t pid) {
+ /* Checks whether a PID is still valid at all, including a zombie */
+
+ if (pid < 0)
+ return false;
+
+ if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */
+ return true;
+
+ if (pid == getpid_cached())
+ return true;
+
+ if (kill(pid, 0) >= 0)
+ return true;
+
+ return errno != ESRCH;
+}
+
+bool pid_is_alive(pid_t pid) {
+ int r;
+
+ /* Checks whether a PID is still valid and not a zombie */
+
+ if (pid < 0)
+ return false;
+
+ if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */
+ return true;
+
+ if (pid == getpid_cached())
+ return true;
+
+ r = get_process_state(pid);
+ if (r == -ESRCH || r == 'Z')
+ return false;
+
+ return true;
+}
+
+int pid_from_same_root_fs(pid_t pid) {
+ const char *root;
+
+ if (pid < 0)
+ return false;
+
+ if (pid == 0 || pid == getpid_cached())
+ return true;
+
+ root = procfs_file_alloca(pid, "root");
+
+ return files_same(root, "/proc/1/root", 0);
+}
+
+bool is_main_thread(void) {
+ static thread_local int cached = 0;
+
+ if (_unlikely_(cached == 0))
+ cached = getpid_cached() == gettid() ? 1 : -1;
+
+ return cached > 0;
+}
+
+noreturn void freeze(void) {
+
+ log_close();
+
+ /* Make sure nobody waits for us on a socket anymore */
+ close_all_fds(NULL, 0);
+
+ sync();
+
+ for (;;)
+ pause();
+}
+
+bool oom_score_adjust_is_valid(int oa) {
+ return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
+}
+
+unsigned long personality_from_string(const char *p) {
+ int architecture;
+
+ if (!p)
+ return PERSONALITY_INVALID;
+
+ /* Parse a personality specifier. We use our own identifiers that indicate specific ABIs, rather than just
+ * hints regarding the register size, since we want to keep things open for multiple locally supported ABIs for
+ * the same register size. */
+
+ architecture = architecture_from_string(p);
+ if (architecture < 0)
+ return PERSONALITY_INVALID;
+
+ if (architecture == native_architecture())
+ return PER_LINUX;
+#ifdef SECONDARY_ARCHITECTURE
+ if (architecture == SECONDARY_ARCHITECTURE)
+ return PER_LINUX32;
+#endif
+
+ return PERSONALITY_INVALID;
+}
+
+const char* personality_to_string(unsigned long p) {
+ int architecture = _ARCHITECTURE_INVALID;
+
+ if (p == PER_LINUX)
+ architecture = native_architecture();
+#ifdef SECONDARY_ARCHITECTURE
+ else if (p == PER_LINUX32)
+ architecture = SECONDARY_ARCHITECTURE;
+#endif
+
+ if (architecture < 0)
+ return NULL;
+
+ return architecture_to_string(architecture);
+}
+
+void valgrind_summary_hack(void) {
+#ifdef HAVE_VALGRIND_VALGRIND_H
+ if (getpid_cached() == 1 && RUNNING_ON_VALGRIND) {
+ pid_t pid;
+ pid = raw_clone(SIGCHLD);
+ if (pid < 0)
+ log_emergency_errno(errno, "Failed to fork off valgrind helper: %m");
+ else if (pid == 0)
+ exit(EXIT_SUCCESS);
+ else {
+ log_info("Spawned valgrind helper as PID "PID_FMT".", pid);
+ (void) wait_for_terminate(pid, NULL);
+ }
+ }
+#endif
+}
+
+int pid_compare_func(const void *a, const void *b) {
+ const pid_t *p = a, *q = b;
+
+ /* Suitable for usage in qsort() */
+
+ if (*p < *q)
+ return -1;
+ if (*p > *q)
+ return 1;
+ return 0;
+}
+
+int ioprio_parse_priority(const char *s, int *ret) {
+ int i, r;
+
+ assert(s);
+ assert(ret);
+
+ r = safe_atoi(s, &i);
+ if (r < 0)
+ return r;
+
+ if (!ioprio_priority_is_valid(i))
+ return -EINVAL;
+
+ *ret = i;
+ return 0;
+}
+
+/* The cached PID, possible values:
+ *
+ * == UNSET [0] → cache not initialized yet
+ * == BUSY [-1] → some thread is initializing it at the moment
+ * any other → the cached PID
+ */
+
+#define CACHED_PID_UNSET ((pid_t) 0)
+#define CACHED_PID_BUSY ((pid_t) -1)
+
+static pid_t cached_pid = CACHED_PID_UNSET;
+
+static void reset_cached_pid(void) {
+ /* Invoked in the child after a fork(), i.e. at the first moment the PID changed */
+ cached_pid = CACHED_PID_UNSET;
+}
+
+/* We use glibc __register_atfork() + __dso_handle directly here, as they are not included in the glibc
+ * 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__));
+
+pid_t getpid_cached(void) {
+ pid_t current_value;
+
+ /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a
+ * system call each time. This restores glibc behaviour from before 2.24, when getpid() was unconditionally
+ * cached. Starting with 2.24 getpid() started to become prohibitively expensive when used for detecting when
+ * objects were used across fork()s. With this caching the old behaviour is somewhat restored.
+ *
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1443976
+ * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=1d2bc2eae969543b89850e35e532f3144122d80a
+ */
+
+ current_value = __sync_val_compare_and_swap(&cached_pid, CACHED_PID_UNSET, CACHED_PID_BUSY);
+
+ switch (current_value) {
+
+ case CACHED_PID_UNSET: { /* Not initialized yet, then do so now */
+ pid_t new_pid;
+
+ new_pid = getpid();
+
+ if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) {
+ /* OOM? Let's try again later */
+ cached_pid = CACHED_PID_UNSET;
+ return new_pid;
+ }
+
+ cached_pid = new_pid;
+ return new_pid;
+ }
+
+ case CACHED_PID_BUSY: /* Somebody else is currently initializing */
+ return getpid();
+
+ default: /* Properly initialized */
+ return current_value;
+ }
+}
+
+static const char *const ioprio_class_table[] = {
+ [IOPRIO_CLASS_NONE] = "none",
+ [IOPRIO_CLASS_RT] = "realtime",
+ [IOPRIO_CLASS_BE] = "best-effort",
+ [IOPRIO_CLASS_IDLE] = "idle"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
+
+static const char *const sigchld_code_table[] = {
+ [CLD_EXITED] = "exited",
+ [CLD_KILLED] = "killed",
+ [CLD_DUMPED] = "dumped",
+ [CLD_TRAPPED] = "trapped",
+ [CLD_STOPPED] = "stopped",
+ [CLD_CONTINUED] = "continued",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
+
+static const char* const sched_policy_table[] = {
+ [SCHED_OTHER] = "other",
+ [SCHED_BATCH] = "batch",
+ [SCHED_IDLE] = "idle",
+ [SCHED_FIFO] = "fifo",
+ [SCHED_RR] = "rr"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
diff --git a/src/systemd/src/basic/process-util.h b/src/systemd/src/basic/process-util.h
new file mode 100644
index 0000000000..b45d60dbd1
--- /dev/null
+++ b/src/systemd/src/basic/process-util.h
@@ -0,0 +1,127 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <alloca.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+
+#include "format-util.h"
+#include "ioprio.h"
+#include "macro.h"
+
+#define procfs_file_alloca(pid, field) \
+ ({ \
+ pid_t _pid_ = (pid); \
+ const char *_r_; \
+ if (_pid_ == 0) { \
+ _r_ = ("/proc/self/" field); \
+ } else { \
+ _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
+ sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \
+ } \
+ _r_; \
+ })
+
+int get_process_state(pid_t pid);
+int get_process_comm(pid_t pid, char **name);
+int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line);
+int get_process_exe(pid_t pid, char **name);
+int get_process_uid(pid_t pid, uid_t *uid);
+int get_process_gid(pid_t pid, gid_t *gid);
+int get_process_capeff(pid_t pid, char **capeff);
+int get_process_cwd(pid_t pid, char **cwd);
+int get_process_root(pid_t pid, char **root);
+int get_process_environ(pid_t pid, char **environ);
+int get_process_ppid(pid_t pid, pid_t *ppid);
+
+int wait_for_terminate(pid_t pid, siginfo_t *status);
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
+
+void sigkill_wait(pid_t pid);
+void sigkill_waitp(pid_t *pid);
+
+int kill_and_sigcont(pid_t pid, int sig);
+
+int rename_process(const char name[]);
+int is_kernel_thread(pid_t pid);
+
+int getenv_for_pid(pid_t pid, const char *field, char **_value);
+
+bool pid_is_alive(pid_t pid);
+bool pid_is_unwaited(pid_t pid);
+int pid_from_same_root_fs(pid_t pid);
+
+bool is_main_thread(void);
+
+noreturn void freeze(void);
+
+bool oom_score_adjust_is_valid(int oa);
+
+#ifndef PERSONALITY_INVALID
+/* personality(7) documents that 0xffffffffUL is used for querying the
+ * current personality, hence let's use that here as error
+ * indicator. */
+#define PERSONALITY_INVALID 0xffffffffLU
+#endif
+
+unsigned long personality_from_string(const char *p);
+const char *personality_to_string(unsigned long);
+
+int ioprio_class_to_string_alloc(int i, char **s);
+int ioprio_class_from_string(const char *s);
+
+const char *sigchld_code_to_string(int i) _const_;
+int sigchld_code_from_string(const char *s) _pure_;
+
+int sched_policy_to_string_alloc(int i, char **s);
+int sched_policy_from_string(const char *s);
+
+#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
+#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
+
+void valgrind_summary_hack(void);
+
+int pid_compare_func(const void *a, const void *b);
+
+static inline bool nice_is_valid(int n) {
+ return n >= PRIO_MIN && n < PRIO_MAX;
+}
+
+static inline bool ioprio_class_is_valid(int i) {
+ return IN_SET(i, IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE);
+}
+
+static inline bool ioprio_priority_is_valid(int i) {
+ return i >= 0 && i < IOPRIO_BE_NR;
+}
+
+static inline bool pid_is_valid(pid_t p) {
+ return p > 0;
+}
+
+int ioprio_parse_priority(const char *s, int *ret);
+
+pid_t getpid_cached(void);
diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c
index b216be579d..42f484d687 100644
--- a/src/systemd/src/basic/random-util.c
+++ b/src/systemd/src/basic/random-util.c
@@ -42,53 +42,59 @@
#include "random-util.h"
#include "time-util.h"
-int dev_urandom(void *p, size_t n) {
+int acquire_random_bytes(void *p, size_t n, bool high_quality_required) {
static int have_syscall = -1;
_cleanup_close_ int fd = -1;
+ unsigned already_done = 0;
int r;
- /* Gathers some randomness from the kernel. This call will
- * never block, and will always return some data from the
- * kernel, regardless if the random pool is fully initialized
- * or not. It thus makes no guarantee for the quality of the
- * returned entropy, but is good enough for our usual usecases
- * of seeding the hash functions for hashtable */
+ /* Gathers some randomness from the kernel. This call will never block. If
+ * high_quality_required, it will always return some data from the kernel,
+ * regardless of whether the random pool is fully initialized or not.
+ * Otherwise, it will return success if at least some random bytes were
+ * successfully acquired, and an error if the kernel has no entropy whatsover
+ * for us. */
- /* Use the getrandom() syscall unless we know we don't have
- * it, or when the requested size is too large for it. */
- if (have_syscall != 0 || (size_t) (int) n != n) {
+ /* Use the getrandom() syscall unless we know we don't have it. */
+ if (have_syscall != 0) {
r = getrandom(p, n, GRND_NONBLOCK);
- if (r == (int) n) {
+ if (r > 0) {
have_syscall = true;
- return 0;
- }
-
- if (r < 0) {
- if (errno == ENOSYS)
- /* we lack the syscall, continue with
- * reading from /dev/urandom */
- have_syscall = false;
- else if (errno == EAGAIN)
- /* not enough entropy for now. Let's
- * remember to use the syscall the
- * next time, again, but also read
- * from /dev/urandom for now, which
- * doesn't care about the current
- * amount of entropy. */
- have_syscall = true;
- else
- return -errno;
+ if ((size_t) r == n)
+ return 0;
+ if (!high_quality_required) {
+ /* Fill in the remaining bytes using pseudorandom values */
+ pseudorandom_bytes((uint8_t*) p + r, n - r);
+ return 0;
+ }
+
+ already_done = r;
+ } else if (errno == ENOSYS)
+ /* We lack the syscall, continue with reading from /dev/urandom. */
+ have_syscall = false;
+ else if (errno == EAGAIN) {
+ /* The kernel has no entropy whatsoever. Let's remember to
+ * use the syscall the next time again though.
+ *
+ * If high_quality_required is false, return an error so that
+ * random_bytes() can produce some pseudorandom
+ * bytes. Otherwise, fall back to /dev/urandom, which we know
+ * is empty, but the kernel will produce some bytes for us on
+ * a best-effort basis. */
+ have_syscall = true;
+
+ if (!high_quality_required)
+ return -ENODATA;
} else
- /* too short read? */
- return -ENODATA;
+ return -errno;
}
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return errno == ENOENT ? -ENOSYS : -errno;
- return loop_read_exact(fd, p, n, true);
+ return loop_read_exact(fd, (uint8_t*) p + already_done, n - already_done, true);
}
void initialize_srand(void) {
@@ -102,12 +108,13 @@ void initialize_srand(void) {
return;
#ifdef HAVE_SYS_AUXV_H
- /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed the
- * pseudo-random generator. It's better than nothing... */
+ /* The kernel provides us with 16 bytes of entropy in auxv, so let's
+ * try to make use of that to seed the pseudo-random generator. It's
+ * better than nothing... */
auxv = (void*) getauxval(AT_RANDOM);
if (auxv) {
- assert_cc(sizeof(x) < 16);
+ assert_cc(sizeof(x) <= 16);
memcpy(&x, auxv, sizeof(x));
} else
#endif
@@ -121,19 +128,44 @@ void initialize_srand(void) {
srand_called = true;
}
-void random_bytes(void *p, size_t n) {
+/* INT_MAX gives us only 31 bits, so use 24 out of that. */
+#if RAND_MAX >= INT_MAX
+# define RAND_STEP 3
+#else
+/* SHORT_INT_MAX or lower gives at most 15 bits, we just just 8 out of that. */
+# define RAND_STEP 1
+#endif
+
+void pseudorandom_bytes(void *p, size_t n) {
uint8_t *q;
+
+ initialize_srand();
+
+ for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) {
+ unsigned rr;
+
+ rr = (unsigned) rand();
+
+#if RAND_STEP >= 3
+ if ((size_t) (q - (uint8_t*) p + 2) < n)
+ q[2] = rr >> 16;
+#endif
+#if RAND_STEP >= 2
+ if ((size_t) (q - (uint8_t*) p + 1) < n)
+ q[1] = rr >> 8;
+#endif
+ q[0] = rr;
+ }
+}
+
+void random_bytes(void *p, size_t n) {
int r;
- r = dev_urandom(p, n);
+ r = acquire_random_bytes(p, n, false);
if (r >= 0)
return;
- /* If some idiot made /dev/urandom unavailable to us, he'll
- * get a PRNG instead. */
-
- initialize_srand();
-
- for (q = p; q < (uint8_t*) p + n; q ++)
- *q = rand();
+ /* If some idiot made /dev/urandom unavailable to us, or the
+ * kernel has no entropy, use a PRNG instead. */
+ return pseudorandom_bytes(p, n);
}
diff --git a/src/systemd/src/basic/random-util.h b/src/systemd/src/basic/random-util.h
index 3cee4c5014..804e225fc1 100644
--- a/src/systemd/src/basic/random-util.h
+++ b/src/systemd/src/basic/random-util.h
@@ -19,10 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
-int dev_urandom(void *p, size_t n);
+int acquire_random_bytes(void *p, size_t n, bool high_quality_required);
+void pseudorandom_bytes(void *p, size_t n);
void random_bytes(void *p, size_t n);
void initialize_srand(void);
diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c
index e5847dce00..016e64aa03 100644
--- a/src/systemd/src/basic/socket-util.c
+++ b/src/systemd/src/basic/socket-util.c
@@ -48,6 +48,12 @@
#include "utf8.h"
#include "util.h"
+#ifdef ENABLE_IDN
+# define IDN_FLAGS (NI_IDN|NI_IDN_USE_STD3_ASCII_RULES)
+#else
+# define IDN_FLAGS 0
+#endif
+
int socket_address_parse(SocketAddress *a, const char *s) {
char *e, *n;
unsigned u;
@@ -406,7 +412,7 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
return false;
if (a->sockaddr.un.sun_path[0]) {
- if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
+ if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, 0))
return false;
} else {
if (a->size != b->size)
@@ -723,8 +729,7 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret)
assert(_ret);
- r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
- NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
+ r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0, IDN_FLAGS);
if (r != 0) {
int saved_errno = errno;
diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h
index 73c3a339fc..43edc05c63 100644
--- a/src/systemd/src/basic/socket-util.h
+++ b/src/systemd/src/basic/socket-util.h
@@ -27,6 +27,7 @@
#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"
@@ -42,6 +43,8 @@ union sockaddr_union {
struct sockaddr_storage storage;
struct sockaddr_ll ll;
struct sockaddr_vm vm;
+ /* Ensure there is enough space to store Infiniband addresses */
+ uint8_t ll_buffer[offsetof(struct sockaddr_ll, sll_addr) + CONST_MAX(ETH_ALEN, INFINIBAND_ALEN)];
};
typedef struct SocketAddress {
@@ -147,6 +150,23 @@ int flush_accept(int fd);
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
+/*
+ * Certain hardware address types (e.g Infiniband) do not fit into sll_addr
+ * (8 bytes) and run over the structure. This macro returns the correct size that
+ * must be passed to kernel.
+ */
+#define SOCKADDR_LL_LEN(sa) \
+ ({ \
+ const struct sockaddr_ll *_sa = &(sa); \
+ size_t _mac_len = sizeof(_sa->sll_addr); \
+ assert(_sa->sll_family == AF_PACKET); \
+ if (be16toh(_sa->sll_hatype) == ARPHRD_ETHER) \
+ _mac_len = MAX(_mac_len, (size_t) ETH_ALEN); \
+ if (be16toh(_sa->sll_hatype) == ARPHRD_INFINIBAND) \
+ _mac_len = MAX(_mac_len, (size_t) INFINIBAND_ALEN); \
+ offsetof(struct sockaddr_ll, sll_addr) + _mac_len; \
+ })
+
/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
#define SOCKADDR_UN_LEN(sa) \
({ \
diff --git a/src/systemd/src/basic/string-util.c b/src/systemd/src/basic/string-util.c
index 9d2f4bc8f9..5808b1280e 100644
--- a/src/systemd/src/basic/string-util.c
+++ b/src/systemd/src/basic/string-util.c
@@ -215,7 +215,7 @@ char *strnappend(const char *s, const char *suffix, size_t b) {
}
char *strappend(const char *s, const char *suffix) {
- return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+ return strnappend(s, suffix, strlen_ptr(suffix));
}
char *strjoin_real(const char *x, ...) {
@@ -542,7 +542,7 @@ char *ellipsize(const char *s, size_t length, unsigned percent) {
return ellipsize_mem(s, strlen(s), length, percent);
}
-bool nulstr_contains(const char*nulstr, const char *needle) {
+bool nulstr_contains(const char *nulstr, const char *needle) {
const char *i;
if (!nulstr)
@@ -558,7 +558,7 @@ bool nulstr_contains(const char*nulstr, const char *needle) {
char* strshorten(char *s, size_t l) {
assert(s);
- if (l < strlen(s))
+ if (strnlen(s, l+1) > l)
s[l] = 0;
return s;
@@ -635,6 +635,11 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
if (!f)
return NULL;
+ /* Note we use the _unlocked() stdio variants on f for performance
+ * reasons. It's safe to do so since we created f here and it
+ * doesn't leave our scope.
+ */
+
for (i = *ibuf; i < *ibuf + isz + 1; i++) {
switch (state) {
@@ -645,21 +650,21 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
else if (*i == '\x1B')
state = STATE_ESCAPE;
else if (*i == '\t')
- fputs(" ", f);
+ fputs_unlocked(" ", f);
else
- fputc(*i, f);
+ fputc_unlocked(*i, f);
break;
case STATE_ESCAPE:
if (i >= *ibuf + isz) { /* EOT */
- fputc('\x1B', f);
+ fputc_unlocked('\x1B', f);
break;
} else if (*i == '[') {
state = STATE_BRACKET;
begin = i + 1;
} else {
- fputc('\x1B', f);
- fputc(*i, f);
+ fputc_unlocked('\x1B', f);
+ fputc_unlocked(*i, f);
state = STATE_OTHER;
}
@@ -669,8 +674,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
if (i >= *ibuf + isz || /* EOT */
(!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
- fputc('\x1B', f);
- fputc('[', f);
+ fputc_unlocked('\x1B', f);
+ fputc_unlocked('[', f);
state = STATE_OTHER;
i = begin-1;
} else if (*i == 'm')
@@ -702,7 +707,7 @@ char *strextend(char **x, ...) {
assert(x);
- l = f = *x ? strlen(*x) : 0;
+ l = f = strlen_ptr(*x);
va_start(ap, x);
for (;;) {
diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h
index be44dedff4..34eb952ce9 100644
--- a/src/systemd/src/basic/string-util.h
+++ b/src/systemd/src/basic/string-util.h
@@ -158,7 +158,7 @@ bool string_has_cc(const char *p, const char *ok) _pure_;
char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
char *ellipsize(const char *s, size_t length, unsigned percent);
-bool nulstr_contains(const char*nulstr, const char *needle);
+bool nulstr_contains(const char *nulstr, const char *needle);
char* strshorten(char *s, size_t l);
@@ -200,3 +200,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
bool string_is_safe(const char *p) _pure_;
+
+static inline size_t strlen_ptr(const char *s) {
+ if (!s)
+ return 0;
+
+ return strlen(s);
+}
diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c
index 0eec868eed..c63f11c6ad 100644
--- a/src/systemd/src/basic/strv.c
+++ b/src/systemd/src/basic/strv.c
@@ -770,11 +770,7 @@ static int str_compare(const void *_a, const void *_b) {
}
char **strv_sort(char **l) {
-
- if (strv_isempty(l))
- return l;
-
- qsort(l, strv_length(l), sizeof(char*), str_compare);
+ qsort_safe(l, strv_length(l), sizeof(char*), str_compare);
return l;
}
diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c
index 8d55af8492..68ba86f6a5 100644
--- a/src/systemd/src/basic/time-util.c
+++ b/src/systemd/src/basic/time-util.c
@@ -107,7 +107,7 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
ts->realtime = u;
delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
- ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta);
+ ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
return ts;
}
@@ -124,8 +124,8 @@ triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u)
ts->realtime = u;
delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
- ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta);
- ts->boottime = clock_boottime_supported() ? usec_sub(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
+ ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
+ ts->boottime = clock_boottime_supported() ? usec_sub_signed(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
return ts;
}
@@ -141,7 +141,7 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
ts->monotonic = u;
delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
- ts->realtime = usec_sub(now(CLOCK_REALTIME), delta);
+ ts->realtime = usec_sub_signed(now(CLOCK_REALTIME), delta);
return ts;
}
@@ -156,8 +156,8 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
dual_timestamp_get(ts);
delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
- ts->realtime = usec_sub(ts->realtime, delta);
- ts->monotonic = usec_sub(ts->monotonic, delta);
+ ts->realtime = usec_sub_signed(ts->realtime, delta);
+ ts->monotonic = usec_sub_signed(ts->monotonic, delta);
return ts;
}
@@ -241,7 +241,7 @@ usec_t timeval_load(const struct timeval *tv) {
struct timeval *timeval_store(struct timeval *tv, usec_t u) {
assert(tv);
- if (u == USEC_INFINITY||
+ if (u == USEC_INFINITY ||
u / USEC_PER_SEC > TIME_T_MAX) {
tv->tv_sec = (time_t) -1;
tv->tv_usec = (suseconds_t) -1;
@@ -864,10 +864,10 @@ finish:
if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
return -EINVAL;
- if (ret > minus)
+ if (ret >= minus)
ret -= minus;
else
- ret = 0;
+ return -EINVAL;
*usec = ret;
@@ -1009,6 +1009,16 @@ int parse_sec(const char *t, usec_t *usec) {
return parse_time(t, usec, USEC_PER_SEC);
}
+int parse_sec_fix_0(const char *t, usec_t *usec) {
+ t += strspn(t, WHITESPACE);
+ if (streq(t, "0")) {
+ *usec = USEC_INFINITY;
+ return 0;
+ }
+
+ return parse_sec(t, usec);
+}
+
int parse_nsec(const char *t, nsec_t *nsec) {
static const struct {
const char *suffix;
@@ -1351,3 +1361,22 @@ unsigned long usec_to_jiffies(usec_t u) {
return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
}
+
+usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
+ usec_t a, b;
+
+ if (x == USEC_INFINITY)
+ return USEC_INFINITY;
+ if (map_clock_id(from) == map_clock_id(to))
+ return x;
+
+ a = now(from);
+ b = now(to);
+
+ if (x > a)
+ /* x lies in the future */
+ return usec_add(b, usec_sub_unsigned(x, a));
+ else
+ /* x lies in the past */
+ return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
+}
diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h
index 7463507f51..3b7f0e99c0 100644
--- a/src/systemd/src/basic/time-util.h
+++ b/src/systemd/src/basic/time-util.h
@@ -133,6 +133,7 @@ int timestamp_deserialize(const char *value, usec_t *timestamp);
int parse_timestamp(const char *t, usec_t *usec);
int parse_sec(const char *t, usec_t *usec);
+int parse_sec_fix_0(const char *t, usec_t *usec);
int parse_time(const char *t, usec_t *usec, usec_t default_unit);
int parse_nsec(const char *t, nsec_t *nsec);
@@ -145,6 +146,8 @@ bool clock_boottime_supported(void);
bool clock_supported(clockid_t clock);
clockid_t clock_boottime_or_monotonic(void);
+usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to);
+
#define xstrftime(buf, fmt, tm) \
assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \
"xstrftime: " #buf "[] must be big enough")
@@ -169,19 +172,23 @@ static inline usec_t usec_add(usec_t a, usec_t b) {
return c;
}
-static inline usec_t usec_sub(usec_t timestamp, int64_t delta) {
- if (delta < 0)
- return usec_add(timestamp, (usec_t) (-delta));
+static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) {
if (timestamp == USEC_INFINITY) /* Make sure infinity doesn't degrade */
return USEC_INFINITY;
-
- if (timestamp < (usec_t) delta)
+ if (timestamp < delta)
return 0;
return timestamp - delta;
}
+static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
+ if (delta < 0)
+ return usec_add(timestamp, (usec_t) (-delta));
+ else
+ return usec_sub_unsigned(timestamp, (usec_t) delta);
+}
+
#if SIZEOF_TIME_T == 8
/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit year
* territory. However, since we want to stay away from this in all timezones we take one day off. */
diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c
index 3dce0ea92e..2f45128ed4 100644
--- a/src/systemd/src/basic/util.c
+++ b/src/systemd/src/basic/util.c
@@ -219,7 +219,7 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
/* Spawns a temporary TTY agent, making sure it goes away when
* we go away */
- parent_pid = getpid();
+ parent_pid = getpid_cached();
/* First we temporarily block all signals, so that the new
* child has them blocked initially. This way, we can be sure
@@ -541,7 +541,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
return -ENOMEM;
- r = files_same(userns_fd_path, "/proc/self/ns/user");
+ r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
if (r < 0)
return r;
if (r)
diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c
index 65405dcce0..a440a20f96 100644
--- a/src/systemd/src/libsystemd-network/dhcp-network.c
+++ b/src/systemd/src/libsystemd-network/dhcp-network.c
@@ -108,14 +108,16 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
if (r < 0)
return -errno;
- link->ll.sll_family = AF_PACKET;
- link->ll.sll_protocol = htobe16(ETH_P_IP);
- link->ll.sll_ifindex = ifindex;
- link->ll.sll_hatype = htobe16(arp_type);
- link->ll.sll_halen = mac_addr_len;
+ link->ll = (struct sockaddr_ll) {
+ .sll_family = AF_PACKET,
+ .sll_protocol = htobe16(ETH_P_IP),
+ .sll_ifindex = ifindex,
+ .sll_hatype = htobe16(arp_type),
+ .sll_halen = mac_addr_len,
+ };
memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
- r = bind(s, &link->sa, sizeof(link->ll));
+ r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
if (r < 0)
return -errno;
@@ -221,7 +223,7 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
assert(packet);
assert(len);
- r = sendto(s, packet, len, 0, &link->sa, sizeof(link->ll));
+ r = sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll));
if (r < 0)
return -errno;
diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c
index 53e29377b3..f1fecba6fa 100644
--- a/src/systemd/src/libsystemd-network/lldp-neighbor.c
+++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c
@@ -249,10 +249,9 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) {
log_lldp("End marker TLV not zero-sized, ignoring datagram.");
return -EBADMSG;
}
- if (left != 0) {
- log_lldp("Trailing garbage in datagram, ignoring datagram.");
- return -EBADMSG;
- }
+
+ /* Note that after processing the SD_LLDP_TYPE_END left could still be > 0
+ * as the message may contain padding (see IEEE 802.1AB-2016, sec. 8.5.12) */
goto end_marker;
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
index 1661874a55..6f0e51720a 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
@@ -926,16 +926,16 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_dns(lease, &addresses);
if (r > 0) {
- fputs("DNS=", f);
+ fputs_unlocked("DNS=", f);
serialize_in_addrs(f, addresses, r);
- fputs("\n", f);
+ fputs_unlocked("\n", f);
}
r = sd_dhcp_lease_get_ntp(lease, &addresses);
if (r > 0) {
- fputs("NTP=", f);
+ fputs_unlocked("NTP=", f);
serialize_in_addrs(f, addresses, r);
- fputs("\n", f);
+ fputs_unlocked("\n", f);
}
r = sd_dhcp_lease_get_domainname(lease, &string);
@@ -944,9 +944,9 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
if (r > 0) {
- fputs("DOMAIN_SEARCH_LIST=", f);
+ fputs_unlocked("DOMAIN_SEARCH_LIST=", f);
fputstrv(f, search_domains, NULL, NULL);
- fputs("\n", f);
+ fputs_unlocked("\n", f);
}
r = sd_dhcp_lease_get_hostname(lease, &string);
diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c
index b4686d0065..320a1ca5c0 100644
--- a/src/systemd/src/libsystemd/sd-event/sd-event.c
+++ b/src/systemd/src/libsystemd/sd-event/sd-event.c
@@ -436,7 +436,7 @@ _public_ int sd_event_new(sd_event** ret) {
e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1;
e->realtime.next = e->boottime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = USEC_INFINITY;
e->realtime.wakeup = e->boottime.wakeup = e->monotonic.wakeup = e->realtime_alarm.wakeup = e->boottime_alarm.wakeup = WAKEUP_CLOCK_DATA;
- e->original_pid = getpid();
+ e->original_pid = getpid_cached();
e->perturb = USEC_INFINITY;
r = prioq_ensure_allocated(&e->pending, pending_prioq_compare);
@@ -493,7 +493,7 @@ static bool event_pid_changed(sd_event *e) {
/* We don't support people creating an event loop and keeping
* it around over a fork(). Let's complain. */
- return e->original_pid != getpid();
+ return e->original_pid != getpid_cached();
}
static void source_io_unregister(sd_event_source *s) {
diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
index cc89f2de2e..b1f6c5305f 100644
--- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
@@ -289,7 +289,7 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
assert_return(ret, -EINVAL);
- r = dev_urandom(&t, sizeof(t));
+ r = acquire_random_bytes(&t, sizeof t, true);
if (r < 0)
return r;
diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c
index 40aec3a1ea..139d286af8 100644
--- a/src/systemd/src/shared/dns-domain.c
+++ b/src/systemd/src/shared/dns-domain.c
@@ -1274,18 +1274,44 @@ int dns_name_apply_idna(const char *name, char **ret) {
#if defined(HAVE_LIBIDN2)
int r;
+ _cleanup_free_ char *t = NULL;
assert(name);
assert(ret);
- r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) ret,
+ r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
- if (r == IDN2_OK)
+ log_debug("idn2_lookup_u8: %s → %s", name, t);
+ if (r == IDN2_OK) {
+ if (!startswith(name, "xn--")) {
+ _cleanup_free_ char *s = NULL;
+
+ r = idn2_to_unicode_8z8z(t, &s, 0);
+ if (r != IDN2_OK) {
+ log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
+ t, r, idn2_strerror(r));
+ return 0;
+ }
+
+ if (!streq_ptr(name, s)) {
+ log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.",
+ name, t, s);
+ return 0;
+ }
+ }
+
+ *ret = t;
+ t = NULL;
return 1; /* *ret has been written */
- else if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
+ }
+
+ log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r));
+ if (r == IDN2_2HYPHEN)
+ /* The name has two hypens — forbidden by IDNA2008 in some cases */
+ return 0;
+ if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
return -ENOSPC;
- else
- return -EINVAL;
+ return -EINVAL;
#elif defined(HAVE_LIBIDN)
_cleanup_free_ char *buf = NULL;
size_t n = 0, allocated = 0;
@@ -1322,7 +1348,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
else
buf[n++] = '.';
- n +=r;
+ n += r;
}
if (n > DNS_HOSTNAME_MAX)
@@ -1335,7 +1361,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
*ret = buf;
buf = NULL;
- return (int) n;
+ return 1;
#else
return 0;
#endif