From 646bba41fd162fe1b8e303ff90914253e5fc669e Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 9 Sep 2019 12:53:08 +0200 Subject: [PATCH] dmesg: add --noescape We have no way how to print the kernel message buffer in really raw way. The new option --noescape disables all \x translations. Addresses: https://github.com/karelzak/util-linux/issues/858 Signed-off-by: Karel Zak --- bash-completion/dmesg | 1 + sys-utils/dmesg.1 | 9 ++++++- sys-utils/dmesg.c | 63 ++++++++++++++++++++++++------------------- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/bash-completion/dmesg b/bash-completion/dmesg index 5073e5b3e4..604307d668 100644 --- a/bash-completion/dmesg +++ b/bash-completion/dmesg @@ -45,6 +45,7 @@ _dmesg_module() --color --level --console-level + --noespace --nopager --raw --syslog diff --git a/sys-utils/dmesg.1 b/sys-utils/dmesg.1 index a93821aeae..05ef911f75 100644 --- a/sys-utils/dmesg.1 +++ b/sys-utils/dmesg.1 @@ -113,12 +113,19 @@ option is used, will .I not print or clear the kernel ring buffer. +.IP "\fB\-\-noescape\fR" +The unprintable and potentially unsafe characters (e.g. broken multi-byte +sequences, terminal controlling chars, etc.) are escaped in format \\x for +security reason by default. This option disables this feature at all. It's +usable for example for debugging purpose together with \fB\-\-raw\fR. Be +careful and don't use it by default. .IP "\fB\-P\fR, \fB\-\-nopager\fR" Do not pipe output into a pager. A pager is enabled by default for \fB\-\-human\fR output. .IP "\fB\-p\fR, \fB\-\-force\-prefix\fR" Add facility, level or timestamp information to each line of a multi-line message. .IP "\fB\-r\fR, \fB\-\-raw\fR" -Print the raw message buffer, i.e. do not strip the log-level prefixes. +Print the raw message buffer, i.e. do not strip the log-level prefixes, but +all unprintable characters are still escaped (see also \fB\-\-noescape\fR). Note that the real raw format depends on the method how .BR dmesg (1) diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c index d12ca8025a..55cf127f32 100644 --- a/sys-utils/dmesg.c +++ b/sys-utils/dmesg.c @@ -191,6 +191,7 @@ struct dmesg_control { unsigned int follow:1, /* wait for new messages */ raw:1, /* raw mode */ + noesc:1, /* no escape */ fltr_lev:1, /* filter out by levels[] */ fltr_fac:1, /* filter out by facilities[] */ decode:1, /* use "facility: level: " prefix */ @@ -286,6 +287,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -P, --nopager do not pipe output into a pager\n"), out); fputs(_(" -p, --force-prefix force timestamp output on each line of multi-line messages\n"), out); fputs(_(" -r, --raw print the raw message buffer\n"), out); + fputs(_(" --noescape don't escape unprintable character\n"), out); fputs(_(" -S, --syslog force to use syslog(2) rather than /dev/kmsg\n"), out); fputs(_(" -s, --buffer-size buffer size to query the kernel ring buffer\n"), out); fputs(_(" -u, --userspace display userspace messages\n"), out); @@ -616,7 +618,7 @@ static int fwrite_hex(const char *buf, size_t size, FILE *out) /* * Prints to 'out' and non-printable chars are replaced with \x sequences. */ -static void safe_fwrite(const char *buf, size_t size, int indent, FILE *out) +static void safe_fwrite(struct dmesg_control *ctl, const char *buf, size_t size, int indent, FILE *out) { size_t i; #ifdef HAVE_WIDECHAR @@ -626,30 +628,32 @@ static void safe_fwrite(const char *buf, size_t size, int indent, FILE *out) for (i = 0; i < size; i++) { const char *p = buf + i; int rc, hex = 0; - size_t len; + size_t len = 1; + if (!ctl->noesc) { #ifdef HAVE_WIDECHAR - wchar_t wc; - len = mbrtowc(&wc, p, size - i, &s); - - if (len == 0) /* L'\0' */ - return; - - if (len == (size_t)-1 || len == (size_t)-2) { /* invalid sequence */ - memset(&s, 0, sizeof (s)); - len = hex = 1; - i += len - 1; - } else if (len > 1) { - if (!iswprint(wc) && !iswspace(wc)) /* non-printable multibyte */ - hex = 1; - i += len - 1; - } else + wchar_t wc; + len = mbrtowc(&wc, p, size - i, &s); + + if (len == 0) /* L'\0' */ + return; + + if (len == (size_t)-1 || len == (size_t)-2) { /* invalid sequence */ + memset(&s, 0, sizeof (s)); + len = hex = 1; + i += len - 1; + } else if (len > 1) { + if (!iswprint(wc) && !iswspace(wc)) /* non-printable multibyte */ + hex = 1; + i += len - 1; + } else #endif - { - len = 1; - if (!isprint((unsigned char) *p) && - !isspace((unsigned char) *p)) /* non-printable */ - hex = 1; + { + len = 1; + if (!isprint((unsigned char) *p) && + !isspace((unsigned char) *p)) /* non-printable */ + hex = 1; + } } if (hex) @@ -787,7 +791,7 @@ static void raw_print(struct dmesg_control *ctl, const char *buf, size_t size) /* * Print whole ring buffer */ - safe_fwrite(buf, size, 0, stdout); + safe_fwrite(ctl, buf, size, 0, stdout); lastc = buf[size - 1]; } else { /* @@ -797,7 +801,7 @@ static void raw_print(struct dmesg_control *ctl, const char *buf, size_t size) size_t sz = size > ctl->pagesize ? ctl->pagesize : size; char *x = ctl->mmap_buff; - safe_fwrite(x, sz, 0, stdout); + safe_fwrite(ctl, x, sz, 0, stdout); lastc = x[sz - 1]; size -= sz; ctl->mmap_buff += sz; @@ -1039,7 +1043,7 @@ full_output: if (subsys) { dmesg_enable_color(DMESG_COLOR_SUBSYS); - safe_fwrite(line, subsys - line, ctl->indent, stdout); + safe_fwrite(ctl, line, subsys - line, ctl->indent, stdout); color_disable(); mesg_size -= subsys - line; @@ -1047,11 +1051,11 @@ full_output: } /* Error, alert .. etc. colors */ has_color = set_level_color(rec->level, line, mesg_size) == 0; - safe_fwrite(line, mesg_size, ctl->indent, stdout); + safe_fwrite(ctl, line, mesg_size, ctl->indent, stdout); if (has_color) color_disable(); } else - safe_fwrite(line, mesg_size, ctl->indent, stdout); + safe_fwrite(ctl, line, mesg_size, ctl->indent, stdout); /* Get the next line */ if (ctl->force_prefix) { @@ -1313,6 +1317,7 @@ int main(int argc, char *argv[]) int colormode = UL_COLORMODE_UNDEF; enum { OPT_TIME_FORMAT = CHAR_MAX + 1, + OPT_NOESC }; static const struct option longopts[] = { @@ -1336,6 +1341,7 @@ int main(int argc, char *argv[]) { "reltime", no_argument, NULL, 'e' }, { "show-delta", no_argument, NULL, 'd' }, { "ctime", no_argument, NULL, 'T' }, + { "noescape", no_argument, NULL, OPT_NOESC }, { "notime", no_argument, NULL, 't' }, { "nopager", no_argument, NULL, 'P' }, { "userspace", no_argument, NULL, 'u' }, @@ -1461,6 +1467,9 @@ int main(int argc, char *argv[]) case OPT_TIME_FORMAT: ctl.time_fmt = which_time_format(optarg); break; + case OPT_NOESC: + ctl.noesc = 1; + break; case 'h': usage(); -- 2.39.2