aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-05-24 10:41:30 +0200
committerGitHub <noreply@github.com>2019-05-24 10:41:30 +0200
commit05332e243cfcea70f900a741b917d04291a1f9e0 (patch)
tree880e2d5d1c55fc79b9b402598eafdcf7b27f92b9
parentDrop support for /usr/sbin/halt.local (diff)
parentbasic/utf8: reduce memory usage (diff)
downloadsystemd-05332e243cfcea70f900a741b917d04291a1f9e0.tar.xz
systemd-05332e243cfcea70f900a741b917d04291a1f9e0.zip
Merge pull request #12590 from keszybz/unicode-cmdlines
Use unicode for cmdline printing
-rw-r--r--TODO5
-rw-r--r--src/basic/env-util.c4
-rw-r--r--src/basic/env-util.h7
-rw-r--r--src/basic/escape.c71
-rw-r--r--src/basic/escape.h6
-rw-r--r--src/basic/proc-cmdline.c2
-rw-r--r--src/basic/process-util.c183
-rw-r--r--src/basic/process-util.h7
-rw-r--r--src/basic/string-util.h13
-rw-r--r--src/basic/utf8.c76
-rw-r--r--src/basic/utf8.h5
-rw-r--r--src/cgtop/cgtop.c2
-rw-r--r--src/core/dbus-unit.c2
-rw-r--r--src/coredump/coredump.c4
-rw-r--r--src/journal/journald-context.c11
-rw-r--r--src/shared/cgroup-show.c22
-rw-r--r--src/shared/cgroup-show.h6
-rw-r--r--src/test/test-escape.c44
-rw-r--r--src/test/test-process-util.c143
-rw-r--r--src/test/test-utf8.c62
-rwxr-xr-xtest/TEST-13-NSPAWN-SMOKE/test.sh2
21 files changed, 418 insertions, 259 deletions
diff --git a/TODO b/TODO
index d87a70a0b53..e8f59d0932f 100644
--- a/TODO
+++ b/TODO
@@ -4,6 +4,11 @@ Bugfixes:
manager or system manager can be always set. It would be better to reject
them when parsing config.
+* busctl --user call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager GetUnitProcesses "s" run-rbff1b85427b34ba3adf864281aeda8e7.service
+Failed to set address: No such file or directory
+
+ → improve error message
+
External:
* Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros.
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index fd449dcce07..896eec58356 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -72,7 +72,7 @@ bool env_value_is_valid(const char *e) {
* either. Discounting the shortest possible variable name of
* length 1, the equal sign and trailing NUL this hence leaves
* ARG_MAX-3 as longest possible variable value. */
- if (strlen(e) > (size_t) sysconf(_SC_ARG_MAX) - 3)
+ if (strlen(e) > sc_arg_max() - 3)
return false;
return true;
@@ -95,7 +95,7 @@ bool env_assignment_is_valid(const char *e) {
* be > ARG_MAX, hence the individual variable assignments
* cannot be either, but let's leave room for one trailing NUL
* byte. */
- if (strlen(e) > (size_t) sysconf(_SC_ARG_MAX) - 1)
+ if (strlen(e) > sc_arg_max() - 1)
return false;
return true;
diff --git a/src/basic/env-util.h b/src/basic/env-util.h
index d54f99658bd..92802ed7744 100644
--- a/src/basic/env-util.h
+++ b/src/basic/env-util.h
@@ -4,10 +4,17 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
+#include <unistd.h>
#include "macro.h"
#include "string.h"
+static inline size_t sc_arg_max(void) {
+ long l = sysconf(_SC_ARG_MAX);
+ assert(l > 0);
+ return (size_t) l;
+}
+
bool env_name_is_valid(const char *e);
bool env_value_is_valid(const char *e);
bool env_assignment_is_valid(const char *e);
diff --git a/src/basic/escape.c b/src/basic/escape.c
index 5f715156fbf..33a6f204f55 100644
--- a/src/basic/escape.c
+++ b/src/basic/escape.c
@@ -368,33 +368,78 @@ int cunescape(const char *s, UnescapeFlags flags, char **ret) {
return cunescape_length(s, strlen(s), flags, ret);
}
-char *xescape(const char *s, const char *bad) {
- char *r, *t;
+char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) {
+ char *ans, *t, *prev, *prev2;
const char *f;
- /* Escapes all chars in bad, in addition to \ and all special
- * chars, in \xFF style escaping. May be reversed with
- * cunescape(). */
+ /* Escapes all chars in bad, in addition to \ and all special chars, in \xFF style escaping. May be
+ * reversed with cunescape(). If eight_bits is true, characters >= 127 are let through unchanged.
+ * This corresponds to non-ASCII printable characters in pre-unicode encodings.
+ *
+ * If console_width is reached, output is truncated and "..." is appended. */
- r = new(char, strlen(s) * 4 + 1);
- if (!r)
+ if (console_width == 0)
+ return strdup("");
+
+ ans = new(char, MIN(strlen(s), console_width) * 4 + 1);
+ if (!ans)
return NULL;
- for (f = s, t = r; *f; f++) {
+ memset(ans, '_', MIN(strlen(s), console_width) * 4);
+ ans[MIN(strlen(s), console_width) * 4] = 0;
+
+ for (f = s, t = prev = prev2 = ans; ; f++) {
+ char *tmp_t = t;
+
+ if (!*f) {
+ *t = 0;
+ return ans;
+ }
+
+ if ((unsigned char) *f < ' ' || (!eight_bits && (unsigned char) *f >= 127) ||
+ *f == '\\' || strchr(bad, *f)) {
+ if ((size_t) (t - ans) + 4 > console_width)
+ break;
- if ((*f < ' ') || (*f >= 127) ||
- (*f == '\\') || strchr(bad, *f)) {
*(t++) = '\\';
*(t++) = 'x';
*(t++) = hexchar(*f >> 4);
*(t++) = hexchar(*f);
- } else
+ } else {
+ if ((size_t) (t - ans) + 1 > console_width)
+ break;
+
*(t++) = *f;
+ }
+
+ /* We might need to go back two cycles to fit three dots, so remember two positions */
+ prev2 = prev;
+ prev = tmp_t;
}
- *t = 0;
+ /* We can just write where we want, since chars are one-byte */
+ size_t c = MIN(console_width, 3u); /* If the console is too narrow, write fewer dots */
+ size_t off;
+ if (console_width - c >= (size_t) (t - ans))
+ off = (size_t) (t - ans);
+ else if (console_width - c >= (size_t) (prev - ans))
+ off = (size_t) (prev - ans);
+ else if (console_width - c >= (size_t) (prev2 - ans))
+ off = (size_t) (prev2 - ans);
+ else
+ off = console_width - c;
+ assert(off <= (size_t) (t - ans));
- return r;
+ memcpy(ans + off, "...", c);
+ ans[off + c] = '\0';
+ return ans;
+}
+
+char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit) {
+ if (eight_bit)
+ return xescape_full(str, "", console_width, true);
+ else
+ return utf8_escape_non_printable_full(str, console_width);
}
char *octescape(const char *s, size_t len) {
diff --git a/src/basic/escape.h b/src/basic/escape.h
index 515620993d0..b26054c5df8 100644
--- a/src/basic/escape.h
+++ b/src/basic/escape.h
@@ -46,8 +46,12 @@ int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **r
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit);
-char *xescape(const char *s, const char *bad);
+char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits);
+static inline char *xescape(const char *s, const char *bad) {
+ return xescape_full(s, bad, SIZE_MAX, false);
+}
char *octescape(const char *s, size_t len);
+char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit);
char *shell_escape(const char *s, const char *bad);
char* shell_maybe_quote(const char *s, EscapeStyle style);
diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c
index 16700013641..b82ca4b21b2 100644
--- a/src/basic/proc-cmdline.c
+++ b/src/basic/proc-cmdline.c
@@ -34,7 +34,7 @@ int proc_cmdline(char **ret) {
}
if (detect_container() > 0)
- return get_process_cmdline(1, 0, false, ret);
+ return get_process_cmdline(1, SIZE_MAX, 0, ret);
else
return read_one_line_file("/proc/cmdline", ret);
}
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 052bce6645f..b50537908cc 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -25,10 +25,12 @@
#include "alloc-util.h"
#include "architecture.h"
#include "escape.h"
+#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "ioprio.h"
+#include "locale-util.h"
#include "log.h"
#include "macro.h"
#include "memory-util.h"
@@ -43,6 +45,12 @@
#include "string-util.h"
#include "terminal-util.h"
#include "user-util.h"
+#include "utf8.h"
+
+/* The kernel limits userspace processes to TASK_COMM_LEN (16 bytes), but allows higher values for its own
+ * workers, e.g. "kworker/u9:3-kcryptd/253:0". Let's pick a fixed smallish limit that will work for the kernel.
+ */
+#define COMM_MAX_LEN 128
static int get_process_state(pid_t pid) {
const char *p;
@@ -80,7 +88,7 @@ int get_process_comm(pid_t pid, char **ret) {
assert(ret);
assert(pid >= 0);
- escaped = new(char, TASK_COMM_LEN);
+ escaped = new(char, COMM_MAX_LEN);
if (!escaped)
return -ENOMEM;
@@ -93,28 +101,31 @@ int get_process_comm(pid_t pid, char **ret) {
return r;
/* Escape unprintable characters, just in case, but don't grow the string beyond the underlying size */
- cellescape(escaped, TASK_COMM_LEN, comm);
+ cellescape(escaped, COMM_MAX_LEN, comm);
*ret = TAKE_PTR(escaped);
return 0;
}
-int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
+int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line) {
_cleanup_fclose_ FILE *f = NULL;
- bool space = false;
- char *k;
- _cleanup_free_ char *ans = NULL;
+ _cleanup_free_ char *t = NULL, *ans = NULL;
const char *p;
- int c, r;
+ int r;
+ size_t k;
+
+ /* This is supposed to be a safety guard against runaway command lines. */
+ size_t max_length = sc_arg_max();
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.
+ /* Retrieves a process' command line. Replaces non-utf8 bytes by replacement character (�). If
+ * max_columns is != -1 will return a string of the specified console width at most, abbreviated with
+ * an ellipsis. If PROCESS_CMDLINE_COMM_FALLBACK is specified in flags 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. This will use at most _SC_ARG_MAX bytes of
+ * input data.
*
* 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. */
@@ -126,130 +137,56 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
if (r < 0)
return r;
- if (max_length == 0) {
- /* This is supposed to be a safety guard against runaway command lines. */
- long l = sysconf(_SC_ARG_MAX);
- assert(l > 0);
- max_length = l;
- }
-
- if (max_length == 1) {
+ /* We assume that each four-byte character uses one or two columns. If we ever check for combining
+ * characters, this assumption will need to be adjusted. */
+ if ((size_t) 4 * max_columns + 1 < max_columns)
+ max_length = MIN(max_length, (size_t) 4 * max_columns + 1);
- /* If there's only room for one byte, return the empty string */
- ans = new0(char, 1);
- if (!ans)
- return -ENOMEM;
+ t = new(char, max_length);
+ if (!t)
+ return -ENOMEM;
- *line = TAKE_PTR(ans);
- return 0;
+ k = fread(t, 1, max_length, f);
+ if (k > 0) {
+ /* Arguments are separated by NULs. Let's replace those with spaces. */
+ for (size_t i = 0; i < k - 1; i++)
+ if (t[i] == '\0')
+ t[i] = ' ';
+ t[k] = '\0'; /* Normally, t[k] is already NUL, so this is just a guard in case of short read */
} 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;
-
- ans = mfree(ans);
+ /* We only treat getting nothing as an error. We *could* also get an error after reading some
+ * data, but we ignore that case, as such an error is rather unlikely and we prefer to get
+ * some data rather than none. */
+ if (ferror(f))
+ return -errno;
- if (!comm_fallback)
+ if (!(flags & PROCESS_CMDLINE_COMM_FALLBACK))
return -ENOENT;
- h = get_process_comm(pid, &t);
- if (h < 0)
- return h;
-
- size_t l = strlen(t);
-
- if (l + 3 <= max_length) {
- ans = strjoin("[", t, "]");
- if (!ans)
- return -ENOMEM;
-
- } else if (max_length <= 6) {
- ans = new(char, max_length);
- if (!ans)
- return -ENOMEM;
+ /* Kernel threads have no argv[] */
+ _cleanup_free_ char *t2 = NULL;
- memcpy(ans, "[...]", max_length-1);
- ans[max_length-1] = 0;
- } else {
- t[max_length - 6] = 0;
+ r = get_process_comm(pid, &t2);
+ if (r < 0)
+ return r;
- /* Chop off final spaces */
- delete_trailing_chars(t, WHITESPACE);
+ mfree(t);
+ t = strjoin("[", t2, "]");
+ if (!t)
+ return -ENOMEM;
+ }
- ans = strjoin("[", t, "...]");
- if (!ans)
- return -ENOMEM;
- }
+ delete_trailing_chars(t, WHITESPACE);
- *line = TAKE_PTR(ans);
- return 0;
- }
+ bool eight_bit = (flags & PROCESS_CMDLINE_USE_LOCALE) && !is_locale_utf8();
- k = realloc(ans, strlen(ans) + 1);
- if (!k)
+ ans = escape_non_printable_full(t, max_columns, eight_bit);
+ if (!ans)
return -ENOMEM;
- ans = NULL;
- *line = k;
-
+ (void) str_realloc(&ans);
+ *line = TAKE_PTR(ans);
return 0;
}
@@ -281,7 +218,7 @@ int rename_process(const char name[]) {
* can use PR_SET_NAME, which sets the thread name for the calling thread. */
if (prctl(PR_SET_NAME, name) < 0)
log_debug_errno(errno, "PR_SET_NAME failed: %m");
- if (l >= TASK_COMM_LEN) /* Linux process names can be 15 chars at max */
+ if (l >= TASK_COMM_LEN) /* Linux userspace process names can be 15 chars at max */
truncated = true;
/* Second step, change glibc's ID of the process name. */
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index 83ba93d0d74..2e3bd725054 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -31,8 +31,13 @@
_r_; \
})
+typedef enum ProcessCmdlineFlags {
+ PROCESS_CMDLINE_COMM_FALLBACK = 1 << 0,
+ PROCESS_CMDLINE_USE_LOCALE = 1 << 1,
+} ProcessCmdlineFlags;
+
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_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, 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);
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index a630856236a..47b17c9d3e7 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -257,3 +257,16 @@ static inline void *memory_startswith_no_case(const void *p, size_t sz, const ch
return (uint8_t*) p + n;
}
+
+static inline char* str_realloc(char **p) {
+ /* Reallocate *p to actual size */
+
+ if (!*p)
+ return NULL;
+
+ char *t = realloc(*p, strlen(*p) + 1);
+ if (!t)
+ return NULL;
+
+ return (*p = t);
+}
diff --git a/src/basic/utf8.c b/src/basic/utf8.c
index 090c69d1400..afc24700dd7 100644
--- a/src/basic/utf8.c
+++ b/src/basic/utf8.c
@@ -32,6 +32,7 @@
#include "gunicode.h"
#include "hexdecoct.h"
#include "macro.h"
+#include "string-util.h"
#include "utf8.h"
bool unichar_is_valid(char32_t ch) {
@@ -192,46 +193,93 @@ char *utf8_escape_invalid(const char *str) {
}
*s = '\0';
-
+ (void) str_realloc(&p);
return p;
}
-char *utf8_escape_non_printable(const char *str) {
- char *p, *s;
+static int utf8_char_console_width(const char *str) {
+ char32_t c;
+ int r;
+
+ r = utf8_encoded_to_unichar(str, &c);
+ if (r < 0)
+ return r;
+
+ /* TODO: we should detect combining characters */
+
+ return unichar_iswide(c) ? 2 : 1;
+}
+
+char *utf8_escape_non_printable_full(const char *str, size_t console_width) {
+ char *p, *s, *prev_s;
+ size_t n = 0; /* estimated print width */
assert(str);
- p = s = malloc(strlen(str) * 4 + 1);
+ if (console_width == 0)
+ return strdup("");
+
+ p = s = prev_s = malloc(strlen(str) * 4 + 1);
if (!p)
return NULL;
- while (*str) {
+ for (;;) {
int len;
+ char *saved_s = s;
+
+ if (!*str) /* done! */
+ goto finish;
len = utf8_encoded_valid_unichar(str, (size_t) -1);
if (len > 0) {
if (utf8_is_printable(str, len)) {
+ int w;
+
+ w = utf8_char_console_width(str);
+ assert(w >= 0);
+ if (n + w > console_width)
+ goto truncation;
+
s = mempcpy(s, str, len);
str += len;
+ n += w;
+
} else {
- while (len > 0) {
+ for (; len > 0; len--) {
+ if (n + 4 > console_width)
+ goto truncation;
+
*(s++) = '\\';
*(s++) = 'x';
*(s++) = hexchar((int) *str >> 4);
*(s++) = hexchar((int) *str);
str += 1;
- len--;
+ n += 4;
}
}
} else {
- s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
+ if (n + 1 > console_width)
+ goto truncation;
+
+ s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER));
str += 1;
+ n += 1;
}
+
+ prev_s = saved_s;
}
- *s = '\0';
+ truncation:
+ /* Try to go back one if we don't have enough space for the ellipsis */
+ if (n + 1 >= console_width)
+ s = prev_s;
+
+ s = mempcpy(s, "…", strlen("…"));
+ finish:
+ *s = '\0';
+ (void) str_realloc(&p);
return p;
}
@@ -519,15 +567,15 @@ size_t utf8_console_width(const char *str) {
/* Returns the approximate width a string will take on screen when printed on a character cell
* terminal/console. */
- while (*str != 0) {
- char32_t c;
+ while (*str) {
+ int w;
- if (utf8_encoded_to_unichar(str, &c) < 0)
+ w = utf8_char_console_width(str);
+ if (w < 0)
return (size_t) -1;
+ n += w;
str = utf8_next_char(str);
-
- n += unichar_iswide(c) ? 2 : 1;
}
return n;
diff --git a/src/basic/utf8.h b/src/basic/utf8.h
index 6df70921dbd..62e99b72802 100644
--- a/src/basic/utf8.h
+++ b/src/basic/utf8.h
@@ -22,7 +22,10 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pu
#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
char *utf8_escape_invalid(const char *s);
-char *utf8_escape_non_printable(const char *str);
+char *utf8_escape_non_printable_full(const char *str, size_t console_width);
+static inline char *utf8_escape_non_printable(const char *str) {
+ return utf8_escape_non_printable_full(str, (size_t) -1);
+}
size_t utf8_encode_unichar(char *out_utf8, char32_t g);
size_t utf16_encode_unichar(char16_t *out, char32_t c);
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index c548be07ca1..fff6b505cc3 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -930,7 +930,7 @@ static int run(int argc, char *argv[]) {
r = show_cgroup_get_path_and_warn(arg_machine, arg_root, &root);
if (r < 0)
return log_error_errno(r, "Failed to get root control group path: %m");
- log_debug("Cgroup path: %s", root);
+ log_debug("CGroup path: %s", root);
a = hashmap_new(&group_hash_ops);
b = hashmap_new(&group_hash_ops);
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 16b4a6b1332..a60362fff65 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -901,7 +901,7 @@ static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *
p = buf;
}
- (void) get_process_cmdline(pid, 0, true, &cmdline);
+ (void) get_process_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &cmdline);
return sd_bus_message_append(reply,
"(sus)",
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 9ab704e2076..2cceb49f4b1 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -661,7 +661,7 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
if (r < 0)
return r;
- r = get_process_cmdline(container_pid, 0, false, cmdline);
+ r = get_process_cmdline(container_pid, SIZE_MAX, 0, cmdline);
if (r < 0)
return r;
@@ -1154,7 +1154,7 @@ static int gather_pid_metadata(
if (sd_pid_get_slice(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_SLICE=", t);
- if (get_process_cmdline(pid, 0, false, &t) >= 0)
+ if (get_process_cmdline(pid, SIZE_MAX, 0, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_CMDLINE=", t);
if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0)
diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c
index e6aeb03b779..46edf24cd65 100644
--- a/src/journal/journald-context.c
+++ b/src/journal/journald-context.c
@@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "audit-util.h"
#include "cgroup-util.h"
+#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
@@ -76,18 +77,14 @@ static size_t cache_max(void) {
if (r < 0) {
log_warning_errno(r, "Cannot query /proc/meminfo for MemTotal: %m");
cached = CACHE_MAX_FALLBACK;
- } else {
+ } else
/* Cache entries are usually a few kB, but the process cmdline is controlled by the
* user and can be up to _SC_ARG_MAX, usually 2MB. Let's say that approximately up to
* 1/8th of memory may be used by the cache.
*
* In the common case, this formula gives 64 cache entries for each GB of RAM.
*/
- long l = sysconf(_SC_ARG_MAX);
- assert(l > 0);
-
- cached = CLAMP(mem_total / 8 / (uint64_t) l, CACHE_MAX_MIN, CACHE_MAX_MAX);
- }
+ cached = CLAMP(mem_total / 8 / sc_arg_max(), CACHE_MAX_MIN, CACHE_MAX_MAX);
}
return cached;
@@ -233,7 +230,7 @@ static void client_context_read_basic(ClientContext *c) {
if (get_process_exe(c->pid, &t) >= 0)
free_and_replace(c->exe, t);
- if (get_process_cmdline(c->pid, 0, false, &t) >= 0)
+ if (get_process_cmdline(c->pid, SIZE_MAX, 0, &t) >= 0)
free_and_replace(c->cmdline, t);
if (get_process_capeff(c->pid, &t) >= 0)
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 91a243944c7..e6fdcfa277d 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -29,7 +29,7 @@ static void show_pid_array(
pid_t pids[],
unsigned n_pids,
const char *prefix,
- unsigned n_columns,
+ size_t n_columns,
bool extra,
bool more,
OutputFlags flags) {
@@ -51,17 +51,19 @@ static void show_pid_array(
pid_width = DECIMAL_STR_WIDTH(pids[j]);
if (flags & OUTPUT_FULL_WIDTH)
- n_columns = 0;
+ n_columns = SIZE_MAX;
else {
- if (n_columns > pid_width+2)
- n_columns -= pid_width+2;
+ if (n_columns > pid_width + 3) /* something like "├─1114784 " */
+ n_columns -= pid_width + 3;
else
n_columns = 20;
}
for (i = 0; i < n_pids; i++) {
_cleanup_free_ char *t = NULL;
- (void) get_process_cmdline(pids[i], n_columns, true, &t);
+ (void) get_process_cmdline(pids[i], n_columns,
+ PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_USE_LOCALE,
+ &t);
if (extra)
printf("%s%s ", prefix, special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET));
@@ -75,7 +77,7 @@ static void show_pid_array(
static int show_cgroup_one_by_path(
const char *path,
const char *prefix,
- unsigned n_columns,
+ size_t n_columns,
bool more,
OutputFlags flags) {
@@ -119,7 +121,7 @@ static int show_cgroup_one_by_path(
int show_cgroup_by_path(
const char *path,
const char *prefix,
- unsigned n_columns,
+ size_t n_columns,
OutputFlags flags) {
_cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
@@ -199,7 +201,7 @@ int show_cgroup_by_path(
int show_cgroup(const char *controller,
const char *path,
const char *prefix,
- unsigned n_columns,
+ size_t n_columns,
OutputFlags flags) {
_cleanup_free_ char *p = NULL;
int r;
@@ -217,7 +219,7 @@ static int show_extra_pids(
const char *controller,
const char *path,
const char *prefix,
- unsigned n_columns,
+ size_t n_columns,
const pid_t pids[],
unsigned n_pids,
OutputFlags flags) {
@@ -262,7 +264,7 @@ int show_cgroup_and_extra(
const char *controller,
const char *path,
const char *prefix,
- unsigned n_columns,
+ size_t n_columns,
const pid_t extra_pids[],
unsigned n_extra_pids,
OutputFlags flags) {
diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h
index 3593e9dcf43..dfb26f82910 100644
--- a/src/shared/cgroup-show.h
+++ b/src/shared/cgroup-show.h
@@ -9,10 +9,10 @@
#include "logs-show.h"
#include "output-mode.h"
-int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, OutputFlags flags);
-int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, OutputFlags flags);
+int show_cgroup_by_path(const char *path, const char *prefix, size_t n_columns, OutputFlags flags);
+int show_cgroup(const char *controller, const char *path, const char *prefix, size_t n_columns, OutputFlags flags);
-int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
+int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, size_t n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
int show_cgroup_get_unit_path_and_warn(
sd_bus *bus,
diff --git a/src/test/test-escape.c b/src/test/test-escape.c
index 4ee4aa974d7..add17f9547d 100644
--- a/src/test/test-escape.c
+++ b/src/test/test-escape.c
@@ -6,10 +6,45 @@
#include "tests.h"
static void test_cescape(void) {
- _cleanup_free_ char *escaped;
+ _cleanup_free_ char *t;
- assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313"));
- assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313"));
+ assert_se(t = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313"));
+ assert_se(streq(t, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313"));
+}
+
+static void test_xescape(void) {
+ _cleanup_free_ char *t;
+
+ assert_se(t = xescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313", ""));
+ assert_se(streq(t, "abc\\x5c\"\\x08\\x0c\\x0a\\x0d\\x09\\x0b\\x07\\x03\\x7f\\x9c\\xcb"));
+}
+
+static void test_xescape_full(bool eight_bits) {
+ const char* escaped = !eight_bits ?
+ "a\\x62c\\x5c\"\\x08\\x0c\\x0a\\x0d\\x09\\x0b\\x07\\x03\\x7f\\x9c\\xcb" :
+ "a\\x62c\\x5c\"\\x08\\x0c\\x0a\\x0d\\x09\\x0b\\x07\\x03\177\234\313";
+ const unsigned full_fit = !eight_bits ? 55 : 46;
+
+ for (unsigned i = 0; i < 60; i++) {
+ _cleanup_free_ char *t;
+
+ assert_se(t = xescape_full("abc\\\"\b\f\n\r\t\v\a\003\177\234\313", "b", i, eight_bits));
+
+ log_info("%02d: %s", i, t);
+
+ if (i >= full_fit)
+ assert_se(streq(t, escaped));
+ else if (i >= 3) {
+ /* We need up to four columns, so up to three three columns may be wasted */
+ assert_se(strlen(t) == i || strlen(t) == i - 1 || strlen(t) == i - 2 || strlen(t) == i - 3);
+ assert_se(strneq(t, escaped, i - 3) || strneq(t, escaped, i - 4) ||
+ strneq(t, escaped, i - 5) || strneq(t, escaped, i - 6));
+ assert_se(endswith(t, "..."));
+ } else {
+ assert_se(strlen(t) == i);
+ assert_se(strneq(t, "...", i));
+ }
+ }
}
static void test_cunescape(void) {
@@ -123,6 +158,9 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_cescape();
+ test_xescape();
+ test_xescape_full(false);
+ test_xescape_full(true);
test_cunescape();
test_shell_escape();
test_shell_maybe_quote();
diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c
index 89f6618e2e8..9b644c09bbf 100644
--- a/src/test/test-process-util.c
+++ b/src/test/test-process-util.c
@@ -48,14 +48,14 @@ static void test_get_process_comm(pid_t pid) {
} else
log_warning("%s not exist.", path);
- assert_se(get_process_cmdline(pid, 0, true, &c) >= 0);
+ assert_se(get_process_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c) >= 0);
log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
- assert_se(get_process_cmdline(pid, 8, false, &d) >= 0);
+ assert_se(get_process_cmdline(pid, 8, 0, &d) >= 0);
log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
free(d);
- assert_se(get_process_cmdline(pid, 1, false, &d) >= 0);
+ assert_se(get_process_cmdline(pid, 1, 0, &d) >= 0);
log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d);
assert_se(get_process_ppid(pid, &e) >= 0);
@@ -107,12 +107,12 @@ static void test_get_process_comm_escape(void) {
test_get_process_comm_escape_one("foo", "foo");
test_get_process_comm_escape_one("012345678901234", "012345678901234");
test_get_process_comm_escape_one("0123456789012345", "012345678901234");
- test_get_process_comm_escape_one("äöüß", "\\303\\244\\303…");
- test_get_process_comm_escape_one("xäöüß", "x\\303\\244…");
- test_get_process_comm_escape_one("xxäöüß", "xx\\303\\244…");
- test_get_process_comm_escape_one("xxxäöüß", "xxx\\303\\244…");
- test_get_process_comm_escape_one("xxxxäöüß", "xxxx\\303\\244…");
- test_get_process_comm_escape_one("xxxxxäöüß", "xxxxx\\303…");
+ test_get_process_comm_escape_one("äöüß", "\\303\\244\\303\\266\\303\\274\\303\\237");
+ test_get_process_comm_escape_one("xäöüß", "x\\303\\244\\303\\266\\303\\274\\303\\237");
+ test_get_process_comm_escape_one("xxäöüß", "xx\\303\\244\\303\\266\\303\\274\\303\\237");
+ test_get_process_comm_escape_one("xxxäöüß", "xxx\\303\\244\\303\\266\\303\\274\\303\\237");
+ test_get_process_comm_escape_one("xxxxäöüß", "xxxx\\303\\244\\303\\266\\303\\274\\303\\237");
+ test_get_process_comm_escape_one("xxxxxäöüß", "xxxxx\\303\\244\\303\\266\\303\\274\\303\\237");
assert_se(prctl(PR_SET_NAME, saved) >= 0);
}
@@ -237,150 +237,149 @@ static void test_get_process_cmdline_harder(void) {
assert_se(prctl(PR_SET_NAME, "testa") >= 0);
- assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT);
+ assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) == -ENOENT);
- assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
assert_se(streq(line, "[testa]"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 1, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 0, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ log_info("'%s'", line);
assert_se(streq(line, ""));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 2, true, &line) >= 0);
- assert_se(streq(line, "["));
+ assert_se(get_process_cmdline(getpid_cached(), 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 3, true, &line) >= 0);
- assert_se(streq(line, "[."));
+ assert_se(get_process_cmdline(getpid_cached(), 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "[…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 4, true, &line) >= 0);
- assert_se(streq(line, "[.."));
+ assert_se(get_process_cmdline(getpid_cached(), 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "[t…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 5, true, &line) >= 0);
- assert_se(streq(line, "[..."));
+ assert_se(get_process_cmdline(getpid_cached(), 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "[te…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 6, true, &line) >= 0);
- assert_se(streq(line, "[...]"));
+ assert_se(get_process_cmdline(getpid_cached(), 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "[tes…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 7, true, &line) >= 0);
- assert_se(streq(line, "[t...]"));
+ assert_se(get_process_cmdline(getpid_cached(), 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "[test…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 8, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
assert_se(streq(line, "[testa]"));
line = mfree(line);
- assert_se(write(fd, "\0\0\0\0\0\0\0\0\0", 10) == 10);
-
- assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT);
-
- assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
assert_se(streq(line, "[testa]"));
line = mfree(line);
- assert_se(write(fd, "foo\0bar\0\0\0\0\0", 10) == 10);
+ assert_se(write(fd, "foo\0bar", 8) == 8);
- assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) >= 0);
+ log_info("'%s'", line);
assert_se(streq(line, "foo bar"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
assert_se(streq(line, "foo bar"));
line = mfree(line);
assert_se(write(fd, "quux", 4) == 4);
- assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) >= 0);
+ log_info("'%s'", line);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 1, true, &line) >= 0);
- assert_se(streq(line, ""));
+ assert_se(get_process_cmdline(getpid_cached(), 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 2, true, &line) >= 0);
- assert_se(streq(line, "."));
+ assert_se(get_process_cmdline(getpid_cached(), 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "f…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 3, true, &line) >= 0);
- assert_se(streq(line, ".."));
+ assert_se(get_process_cmdline(getpid_cached(), 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "fo…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 4, true, &line) >= 0);
- assert_se(streq(line, "..."));
+ assert_se(get_process_cmdline(getpid_cached(), 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "foo…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 5, true, &line) >= 0);
- assert_se(streq(line, "f..."));
+ assert_se(get_process_cmdline(getpid_cached(), 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "foo …"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 6, true, &line) >= 0);
- assert_se(streq(line, "fo..."));
+ assert_se(get_process_cmdline(getpid_cached(), 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "foo b…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 7, true, &line) >= 0);
- assert_se(streq(line, "foo..."));
+ assert_se(get_process_cmdline(getpid_cached(), 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "foo ba…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 8, true, &line) >= 0);
- assert_se(streq(line, "foo..."));
+ assert_se(get_process_cmdline(getpid_cached(), 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "foo bar…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 9, true, &line) >= 0);
- assert_se(streq(line, "foo b..."));
+ assert_se(get_process_cmdline(getpid_cached(), 9, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "foo bar …"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 10, true, &line) >= 0);
- assert_se(streq(line, "foo ba..."));
+ assert_se(get_process_cmdline(getpid_cached(), 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "foo bar q…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 11, true, &line) >= 0);
- assert_se(streq(line, "foo bar..."));
+ assert_se(get_process_cmdline(getpid_cached(), 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "foo bar qu…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 12, true, &line) >= 0);
- assert_se(streq(line, "foo bar..."));
+ assert_se(get_process_cmdline(getpid_cached(), 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "foo bar quux"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 13, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 13, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 14, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 14, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 1000, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
assert_se(ftruncate(fd, 0) >= 0);
assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0);
- assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT);
+ assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, 0, &line) == -ENOENT);
- assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
assert_se(streq(line, "[aaaa bbbb cccc]"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 10, true, &line) >= 0);
- assert_se(streq(line, "[aaaa...]"));
+ assert_se(get_process_cmdline(getpid_cached(), 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "[aaaa bbb…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 11, true, &line) >= 0);
- assert_se(streq(line, "[aaaa...]"));
+ assert_se(get_process_cmdline(getpid_cached(), 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "[aaaa bbbb…"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid_cached(), 12, true, &line) >= 0);
- assert_se(streq(line, "[aaaa b...]"));
+ assert_se(get_process_cmdline(getpid_cached(), 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
+ assert_se(streq(line, "[aaaa bbbb …"));
line = mfree(line);
safe_close(fd);
@@ -408,8 +407,10 @@ static void test_rename_process_now(const char *p, int ret) {
assert_se(get_process_comm(0, &comm) >= 0);
log_info("comm = <%s>", comm);
assert_se(strneq(comm, p, TASK_COMM_LEN-1));
+ /* We expect comm to be at most 16 bytes (TASK_COMM_LEN). The kernel may raise this limit in the
+ * future. We'd only check the initial part, at least until we recompile, but this will still pass. */
- r = get_process_cmdline(0, 0, false, &cmdline);
+ r = get_process_cmdline(0, SIZE_MAX, 0, &cmdline);
assert_se(r >= 0);
/* we cannot expect cmdline to be renamed properly without privileges */
if (geteuid() == 0) {
diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c
index d1e48da2a66..b5c4e3dc343 100644
--- a/src/test/test-utf8.c
+++ b/src/test/test-utf8.c
@@ -7,6 +7,8 @@
#include "util.h"
static void test_utf8_is_printable(void) {
+ log_info("/* %s */", __func__);
+
assert_se(utf8_is_printable("ascii is valid\tunicode", 22));
assert_se(utf8_is_printable("\342\204\242", 3));
assert_se(!utf8_is_printable("\341\204", 2));
@@ -14,18 +16,24 @@ static void test_utf8_is_printable(void) {
}
static void test_utf8_is_valid(void) {
+ log_info("/* %s */", __func__);
+
assert_se(utf8_is_valid("ascii is valid unicode"));
assert_se(utf8_is_valid("\342\204\242"));
assert_se(!utf8_is_valid("\341\204"));
}
static void test_ascii_is_valid(void) {
+ log_info("/* %s */", __func__);
+
assert_se( ascii_is_valid("alsdjf\t\vbarr\nba z"));
assert_se(!ascii_is_valid("\342\204\242"));
assert_se(!ascii_is_valid("\341\204"));
}
static void test_ascii_is_valid_n(void) {
+ log_info("/* %s */", __func__);
+
assert_se( ascii_is_valid_n("alsdjf\t\vbarr\nba z", 17));
assert_se( ascii_is_valid_n("alsdjf\t\vbarr\nba z", 16));
assert_se(!ascii_is_valid_n("alsdjf\t\vbarr\nba z", 18));
@@ -36,6 +44,8 @@ static void test_ascii_is_valid_n(void) {
}
static void test_utf8_encoded_valid_unichar(void) {
+ log_info("/* %s */", __func__);
+
assert_se(utf8_encoded_valid_unichar("\342\204\242", 1) == -EINVAL); /* truncated */
assert_se(utf8_encoded_valid_unichar("\342\204\242", 2) == -EINVAL); /* truncated */
assert_se(utf8_encoded_valid_unichar("\342\204\242", 3) == 3);
@@ -53,9 +63,11 @@ static void test_utf8_encoded_valid_unichar(void) {
assert_se(utf8_encoded_valid_unichar("\341\204\341\204", 5) == -EINVAL);
}
-static void test_utf8_escaping(void) {
+static void test_utf8_escape_invalid(void) {
_cleanup_free_ char *p1, *p2, *p3;
+ log_info("/* %s */", __func__);
+
p1 = utf8_escape_invalid("goo goo goo");
puts(p1);
assert_se(utf8_is_valid(p1));
@@ -69,9 +81,11 @@ static void test_utf8_escaping(void) {
assert_se(utf8_is_valid(p3));
}
-static void test_utf8_escaping_printable(void) {
+static void test_utf8_escape_non_printable(void) {
_cleanup_free_ char *p1, *p2, *p3, *p4, *p5, *p6;
+ log_info("/* %s */", __func__);
+
p1 = utf8_escape_non_printable("goo goo goo");
puts(p1);
assert_se(utf8_is_valid(p1));
@@ -97,12 +111,45 @@ static void test_utf8_escaping_printable(void) {
assert_se(utf8_is_valid(p6));
}
+static void test_utf8_escape_non_printable_full(void) {
+ log_info("/* %s */", __func__);
+
+ for (size_t i = 0; i < 20; i++) {
+ _cleanup_free_ char *p;
+
+ p = utf8_escape_non_printable_full("goo goo goo", i);
+ puts(p);
+ assert_se(utf8_is_valid(p));
+ assert_se(utf8_console_width(p) <= i);
+ }
+
+ for (size_t i = 0; i < 20; i++) {
+ _cleanup_free_ char *p;
+
+ p = utf8_escape_non_printable_full("\001 \019\20\a", i);
+ puts(p);
+ assert_se(utf8_is_valid(p));
+ assert_se(utf8_console_width(p) <= i);
+ }
+
+ for (size_t i = 0; i < 20; i++) {
+ _cleanup_free_ char *p;
+
+ p = utf8_escape_non_printable_full("\xef\xbf\x30\x13", i);
+ puts(p);
+ assert_se(utf8_is_valid(p));
+ assert_se(utf8_console_width(p) <= i);
+ }
+}
+
static void test_utf16_to_utf8(void) {
const char16_t utf16[] = { htole16('a'), htole16(0xd800), htole16('b'), htole16(0xdc00), htole16('c'), htole16(0xd801), htole16(0xdc37) };
static const char utf8[] = { 'a', 'b', 'c', 0xf0, 0x90, 0x90, 0xb7 };
_cleanup_free_ char16_t *b = NULL;
_cleanup_free_ char *a = NULL;
+ log_info("/* %s */", __func__);
+
/* Convert UTF-16 to UTF-8, filtering embedded bad chars */
a = utf16_to_utf8(utf16, sizeof(utf16));
assert_se(a);
@@ -120,6 +167,8 @@ static void test_utf16_to_utf8(void) {
}
static void test_utf8_n_codepoints(void) {
+ log_info("/* %s */", __func__);
+
assert_se(utf8_n_codepoints("abc") == 3);
assert_se(utf8_n_codepoints("zażółcić gęślą jaźń") == 19);
assert_se(utf8_n_codepoints("串") == 1);
@@ -129,6 +178,8 @@ static void test_utf8_n_codepoints(void) {
}
static void test_utf8_console_width(void) {
+ log_info("/* %s */", __func__);
+
assert_se(utf8_console_width("abc") == 3);
assert_se(utf8_console_width("zażółcić gęślą jaźń") == 19);
assert_se(utf8_console_width("串") == 2);
@@ -140,6 +191,8 @@ static void test_utf8_console_width(void) {
static void test_utf8_to_utf16(void) {
const char *p;
+ log_info("/* %s */", __func__);
+
FOREACH_STRING(p,
"abc",
"zażółcić gęślą jaźń",
@@ -165,8 +218,9 @@ int main(int argc, char *argv[]) {
test_ascii_is_valid();
test_ascii_is_valid_n();
test_utf8_encoded_valid_unichar();
- test_utf8_escaping();
- test_utf8_escaping_printable();
+ test_utf8_escape_invalid();
+ test_utf8_escape_non_printable();
+ test_utf8_escape_non_printable_full();
test_utf16_to_utf8();
test_utf8_n_codepoints();
test_utf8_console_width();
diff --git a/test/TEST-13-NSPAWN-SMOKE/test.sh b/test/TEST-13-NSPAWN-SMOKE/test.sh
index bd85b92caa5..8252c4b2aaf 100755
--- a/test/TEST-13-NSPAWN-SMOKE/test.sh
+++ b/test/TEST-13-NSPAWN-SMOKE/test.sh
@@ -98,7 +98,7 @@ function run {
return 0
fi
if [[ "$2" = "yes" && "$is_cgns_supported" = "no" ]]; then
- printf "Cgroup namespaces are not supported. Skipping.\n" >&2
+ printf "CGroup namespaces are not supported. Skipping.\n" >&2
return 0
fi