kmsg - export "continuation record" flag to /dev/kmsg
authorKay Sievers <kay@vrfy.org>
Tue, 17 Jul 2012 01:35:30 +0000 (18:35 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 17 Jul 2012 01:35:30 +0000 (18:35 -0700)
In some cases we are forced to store individual records for a continuation
line print.

Export a flag to allow the external re-construction of the line. The flag
allows us to apply a similar logic externally which is used internally when
the console, /proc/kmsg or the syslog() output is printed.

  $ cat /dev/kmsg
  4,165,0,-;Free swap  = 0kB
  4,166,0,-;Total swap = 0kB
  6,167,0,c;[
  4,168,0,+;0
  4,169,0,+;1
  4,170,0,+;2
  4,171,0,+;3
  4,172,0,+;]
  6,173,0,-;[0 1 2 3 ]
  6,174,0,-;Console: colour VGA+ 80x25
  6,175,0,-;console [tty0] enabled

Signed-off-by: Kay Sievers <kay@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/dev-kmsg
kernel/printk.c

index 281ecc5f97092d6634c5a3b540677ec5d9b577db..7e7e07a82e0ec15dbe3255683acd67dba8d2f429 100644 (file)
@@ -58,16 +58,18 @@ Description:        The /dev/kmsg character device node provides userspace access
 
                The output format consists of a prefix carrying the syslog
                prefix including priority and facility, the 64 bit message
-               sequence number and the monotonic timestamp in microseconds.
-               The values are separated by a ','. Future extensions might
-               add more comma separated values before the terminating ';'.
-               Unknown values should be gracefully ignored.
+               sequence number and the monotonic timestamp in microseconds,
+               and a flag field. All fields are separated by a ','.
+
+               Future extensions might add more comma separated values before
+               the terminating ';'. Unknown fields and values should be
+               gracefully ignored.
 
                The human readable text string starts directly after the ';'
                and is terminated by a '\n'. Untrusted values derived from
                hardware or other facilities are printed, therefore
-               all non-printable characters in the log message are escaped
-               by "\x00" C-style hex encoding.
+               all non-printable characters and '\' itself in the log message
+               are escaped by "\x00" C-style hex encoding.
 
                A line starting with ' ', is a continuation line, adding
                key/value pairs to the log message, which provide the machine
@@ -75,11 +77,11 @@ Description:        The /dev/kmsg character device node provides userspace access
                userspace.
 
                Example:
-               7,160,424069;pci_root PNP0A03:00: host bridge window [io  0x0000-0x0cf7] (ignored)
+               7,160,424069,-;pci_root PNP0A03:00: host bridge window [io  0x0000-0x0cf7] (ignored)
                 SUBSYSTEM=acpi
                 DEVICE=+acpi:PNP0A03:00
-               6,339,5140900;NET: Registered protocol family 10
-               30,340,5690716;udevd[80]: starting version 181
+               6,339,5140900,-;NET: Registered protocol family 10
+               30,340,5690716,-;udevd[80]: starting version 181
 
                The DEVICE= key uniquely identifies devices the following way:
                  b12:8        - block dev_t
@@ -87,4 +89,13 @@ Description: The /dev/kmsg character device node provides userspace access
                  n8           - netdev ifindex
                  +sound:card0 - subsystem:devname
 
+               The flags field carries '-' by default. A 'c' indicates a
+               fragment of a line. All following fragments are flagged with
+               '+'. Note, that these hints about continuation lines are not
+               neccessarily correct, and the stream could be interleaved with
+               unrelated messages, but merging the lines in the output
+               usually produces better human readable results. A similar
+               logic is used internally when messages are printed to the
+               console, /proc/kmsg or the syslog() syscall.
+
 Users:         dmesg(1), userspace kernel log consumers
index 6c3d5bf14da2d24f5f84e03f3e1bfa3b714abbd5..a41106e1907791f45e415f1d4ceac2113e37891f 100644 (file)
@@ -361,6 +361,7 @@ static void log_store(int facility, int level,
 struct devkmsg_user {
        u64 seq;
        u32 idx;
+       enum log_flags prev;
        struct mutex lock;
        char buf[8192];
 };
@@ -426,6 +427,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
        struct log *msg;
        u64 ts_usec;
        size_t i;
+       char cont = '-';
        size_t len;
        ssize_t ret;
 
@@ -463,8 +465,25 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
        msg = log_from_idx(user->idx);
        ts_usec = msg->ts_nsec;
        do_div(ts_usec, 1000);
-       len = sprintf(user->buf, "%u,%llu,%llu;",
-                     (msg->facility << 3) | msg->level, user->seq, ts_usec);
+
+       /*
+        * If we couldn't merge continuation line fragments during the print,
+        * export the stored flags to allow an optional external merge of the
+        * records. Merging the records isn't always neccessarily correct, like
+        * when we hit a race during printing. In most cases though, it produces
+        * better readable output. 'c' in the record flags mark the first
+        * fragment of a line, '+' the following.
+        */
+       if (msg->flags & LOG_CONT && !(user->prev & LOG_CONT))
+               cont = 'c';
+       else if ((msg->flags & LOG_CONT) ||
+                ((user->prev & LOG_CONT) && !(msg->flags & LOG_PREFIX)))
+               cont = '+';
+
+       len = sprintf(user->buf, "%u,%llu,%llu,%c;",
+                     (msg->facility << 3) | msg->level,
+                     user->seq, ts_usec, cont);
+       user->prev = msg->flags;
 
        /* escape non-printable characters */
        for (i = 0; i < msg->text_len; i++) {