| From: Kay Sievers <kay@vrfy.org> |
| Subject: kmsg - export "continuation record" flag to /dev/kmsg |
| |
| 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> |
| --- |
| |
| Documentation/ABI/testing/dev-kmsg | 29 ++++++++++++++++++++--------- |
| kernel/printk.c | 23 +++++++++++++++++++++-- |
| 2 files changed, 41 insertions(+), 11 deletions(-) |
| |
| --- a/Documentation/ABI/testing/dev-kmsg |
| +++ b/Documentation/ABI/testing/dev-kmsg |
| @@ -58,16 +58,18 @@ Description: The /dev/kmsg character dev |
| |
| 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 dev |
| 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 dev |
| 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 |
| --- a/kernel/printk.c |
| +++ b/kernel/printk.c |
| @@ -361,6 +361,7 @@ static void log_store(int facility, int |
| 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 |
| 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 |
| 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++) { |