mirror of
https://github.com/systemd/systemd.git
synced 2025-01-12 13:18:14 +03:00
Merge pull request #12590 from keszybz/unicode-cmdlines
Use unicode for cmdline printing
This commit is contained in:
commit
05332e243c
5
TODO
5
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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 (<28>). 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;
|
||||
}
|
||||
/* 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 (max_length == 1) {
|
||||
|
||||
/* If there's only room for one byte, return the empty string */
|
||||
ans = new0(char, 1);
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
*line = TAKE_PTR(ans);
|
||||
return 0;
|
||||
|
||||
} 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);
|
||||
|
||||
if (!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;
|
||||
|
||||
memcpy(ans, "[...]", max_length-1);
|
||||
ans[max_length-1] = 0;
|
||||
} else {
|
||||
t[max_length - 6] = 0;
|
||||
|
||||
/* Chop off final spaces */
|
||||
delete_trailing_chars(t, WHITESPACE);
|
||||
|
||||
ans = strjoin("[", t, "...]");
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*line = TAKE_PTR(ans);
|
||||
return 0;
|
||||
}
|
||||
|
||||
k = realloc(ans, strlen(ans) + 1);
|
||||
if (!k)
|
||||
t = new(char, max_length);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
ans = NULL;
|
||||
*line = k;
|
||||
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 {
|
||||
/* 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 (!(flags & PROCESS_CMDLINE_COMM_FALLBACK))
|
||||
return -ENOENT;
|
||||
|
||||
/* Kernel threads have no argv[] */
|
||||
_cleanup_free_ char *t2 = NULL;
|
||||
|
||||
r = get_process_comm(pid, &t2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
mfree(t);
|
||||
t = strjoin("[", t2, "]");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
delete_trailing_chars(t, WHITESPACE);
|
||||
|
||||
bool eight_bit = (flags & PROCESS_CMDLINE_USE_LOCALE) && !is_locale_utf8();
|
||||
|
||||
ans = escape_non_printable_full(t, max_columns, eight_bit);
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
(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. */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)",
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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..."));
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(get_process_cmdline(getpid_cached(), 13, true, &line) >= 0);
|
||||
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(), 14, 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(), 1000, 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, 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) {
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user