]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
dmesg: don't print non-printable chars, parse records
authorKarel Zak <kzak@redhat.com>
Wed, 13 Jul 2011 13:00:49 +0000 (15:00 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 13 Jul 2011 13:00:49 +0000 (15:00 +0200)
All non-printable chars, non-printable multibyte sequences or invalid
multibyte sequences will be replaced with \x<hex> strings.

Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/dmesg.c

index 94309fd59afa1033ce7fabeef32aa814558a3fed..6be07afe6ec94b10c42e00512be9d274bb60b1a9 100644 (file)
@@ -23,6 +23,8 @@
 #include "nls.h"
 #include "strutils.h"
 #include "xalloc.h"
+#include "widechar.h"
+#include "writeall.h"
 
 /* Close the log.  Currently a NOP. */
 #define SYSLOG_ACTION_CLOSE          0
@@ -68,7 +70,9 @@ static const struct dmesg_name level_names[] =
 };
 
 /* dmesg flags */
-#define DMESG_FL_RAW   (1 << 1)
+#define DMESG_FL_RAW           (1 << 1)
+#define DMESG_FL_LEVEL         (1 << 2)
+#define DMESG_FL_FACILITY      (1 << 3)
 
 static void __attribute__((__noreturn__)) usage(FILE *out)
 {
@@ -152,25 +156,108 @@ static int read_buffer(char **buf, size_t bufsize, int clear)
        return rc;
 }
 
+static int fwrite_hex(const char *buf, size_t size, FILE *out)
+{
+       int i;
+
+       for (i = 0; i < size; i++) {
+               int rc = fprintf(out, "\\x%02x", buf[i]);
+               if (rc < 0)
+                       return rc;
+       }
+       return 0;
+}
+
+static void safe_fwrite(const char *buf, size_t size, FILE *out)
+{
+       int i;
+#ifdef HAVE_WIDECHAR
+       mbstate_t s;
+       memset(&s, 0, sizeof (s));
+#endif
+       for (i = 0; i < size; i++) {
+               const char *p = buf + i;
+               int rc, hex = 0;
+
+#ifdef HAVE_WIDECHAR
+               wchar_t wc;
+               size_t len = mbrtowc(&wc, p, size - i, &s);
+
+               if (len == 0)                           /* L'\0' */
+                       return;
+
+               if (len < 0) {                          /* invalid sequence */
+                       memset(&s, 0, sizeof (s));
+                       len = hex = 1;
+
+               } else if (len > 1 && !iswprint(wc)) {  /* non-printable multibyte */
+                       hex = 1;
+               } else
+#endif
+               {
+                       if (!isprint((unsigned int) *p) &&
+                           !isspace((unsigned int) *p))                /* non-printable */
+                               hex = 1;
+               }
+               if (hex)
+                       rc = fwrite_hex(p, len, out);
+               else
+                       rc = write_all(fileno(out), p, len);
+               if (rc != 0)
+                       err(EXIT_FAILURE, _("write failed"));
+       }
+}
+
 static void print_buffer(const char *buf, size_t size, int flags)
 {
-       int lastc = '\n';
        int i;
+       const char *begin = NULL;
+
+       if (flags & DMESG_FL_RAW) {
+               /* print whole buffer */
+               safe_fwrite(buf, size, stdout);
+               if (buf[size - 1] != '\n')
+                       putchar('\n');
+               return;
+       }
 
        for (i = 0; i < size; i++) {
-               if (!(flags & DMESG_FL_RAW) &&
-                   (i == 0 || buf[i - 1] == '\n') && buf[i] == '<') {
+               const char *p = buf + i, *end = NULL;
+
+               if (!begin)
+                       begin = p;
+               if (*p == '\n')
+                       end = p;
+               if (i + 1 == size) {
+                       end = p + 1;
                        i++;
-                       while (isdigit(buf[i]))
-                               i++;
-                       if (buf[i] == '>')
-                               i++;
                }
-               lastc = buf[i];
-               putchar(lastc);
+               if (!begin || !end)
+                       continue;
+               if (end <= begin)
+                       continue;       /* error or empty line? */
+
+               if ((flags & DMESG_FL_LEVEL) || (flags & DMESG_FL_FACILITY)) {
+                       /* parse facility and level */
+                       ;
+               } else if (*begin == '<') {
+                       /* ignore facility and level */
+                       while (begin < end) {
+                               begin++;
+                               if (*(begin - 1) == '>')
+                                       break;
+                       }
+               }
+
+               if (begin < end) {
+                       size_t sz =  end - begin;
+
+                       safe_fwrite(begin, sz, stdout);
+                       if (*(begin + sz - 1) != '\n')
+                               putchar('\n');
+               }
+               begin = NULL;
        }
-       if (lastc != '\n')
-               putchar('\n');
 }
 
 int main(int argc, char *argv[])