diff options
author | Kay Sievers <kay@vrfy.org> | 2012-05-13 17:30:46 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-05-14 11:42:22 -0400 |
commit | 3ce9a7c0ac28561567fadedf1a99272e4970f740 (patch) | |
tree | 8a3e9bd983941e75943d0a11dacdd85bce7e5c83 /kernel/printk.c | |
parent | 1fce677971e29ceaa7c569741fa9c685a7b1052a (diff) |
printk() - restore prefix/timestamp printing for multi-newline strings
Calls like:
printk("\n *** DEADLOCK ***\n\n");
will print 3 properly indented, separated, syslog + timestamp prefixed lines in
the log output.
Reported-By: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Kay Sievers <kay@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 127 |
1 files changed, 76 insertions, 51 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index c42faf97404a..915a8be10b5f 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -448,7 +448,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
448 | 448 | ||
449 | /* escape non-printable characters */ | 449 | /* escape non-printable characters */ |
450 | for (i = 0; i < msg->text_len; i++) { | 450 | for (i = 0; i < msg->text_len; i++) { |
451 | char c = log_text(msg)[i]; | 451 | unsigned char c = log_text(msg)[i]; |
452 | 452 | ||
453 | if (c < ' ' || c >= 128) | 453 | if (c < ' ' || c >= 128) |
454 | len += sprintf(user->buf + len, "\\x%02x", c); | 454 | len += sprintf(user->buf + len, "\\x%02x", c); |
@@ -461,7 +461,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
461 | bool line = true; | 461 | bool line = true; |
462 | 462 | ||
463 | for (i = 0; i < msg->dict_len; i++) { | 463 | for (i = 0; i < msg->dict_len; i++) { |
464 | char c = log_dict(msg)[i]; | 464 | unsigned char c = log_dict(msg)[i]; |
465 | 465 | ||
466 | if (line) { | 466 | if (line) { |
467 | user->buf[len++] = ' '; | 467 | user->buf[len++] = ' '; |
@@ -785,56 +785,81 @@ static bool printk_time; | |||
785 | #endif | 785 | #endif |
786 | module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); | 786 | module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); |
787 | 787 | ||
788 | static size_t prepend_timestamp(unsigned long long t, char *buf) | 788 | static size_t print_prefix(const struct log *msg, bool syslog, char *buf) |
789 | { | 789 | { |
790 | unsigned long rem_ns; | 790 | size_t len = 0; |
791 | 791 | ||
792 | if (!printk_time) | 792 | if (syslog) { |
793 | return 0; | 793 | if (buf) { |
794 | len += sprintf(buf, "<%u>", msg->level); | ||
795 | } else { | ||
796 | len += 3; | ||
797 | if (msg->level > 9) | ||
798 | len++; | ||
799 | if (msg->level > 99) | ||
800 | len++; | ||
801 | } | ||
802 | } | ||
794 | 803 | ||
795 | if (!buf) | 804 | if (printk_time) { |
796 | return 15; | 805 | if (buf) { |
806 | unsigned long long ts = msg->ts_nsec; | ||
807 | unsigned long rem_nsec = do_div(ts, 1000000000); | ||
797 | 808 | ||
798 | rem_ns = do_div(t, 1000000000); | 809 | len += sprintf(buf + len, "[%5lu.%06lu] ", |
810 | (unsigned long) ts, rem_nsec / 1000); | ||
811 | } else { | ||
812 | len += 15; | ||
813 | } | ||
814 | } | ||
799 | 815 | ||
800 | return sprintf(buf, "[%5lu.%06lu] ", | 816 | return len; |
801 | (unsigned long) t, rem_ns / 1000); | ||
802 | } | 817 | } |
803 | 818 | ||
804 | static int syslog_print_line(u32 idx, char *text, size_t size) | 819 | static size_t msg_print_text(const struct log *msg, bool syslog, |
820 | char *buf, size_t size) | ||
805 | { | 821 | { |
806 | struct log *msg; | 822 | const char *text = log_text(msg); |
807 | size_t len; | 823 | size_t text_size = msg->text_len; |
824 | size_t len = 0; | ||
808 | 825 | ||
809 | msg = log_from_idx(idx); | 826 | do { |
810 | if (!text) { | 827 | const char *next = memchr(text, '\n', text_size); |
811 | /* calculate length only */ | 828 | size_t text_len; |
812 | len = 3; | ||
813 | 829 | ||
814 | if (msg->level > 9) | 830 | if (next) { |
815 | len++; | 831 | text_len = next - text; |
816 | if (msg->level > 99) | 832 | next++; |
817 | len++; | 833 | text_size -= next - text; |
818 | len += prepend_timestamp(0, NULL); | 834 | } else { |
835 | text_len = text_size; | ||
836 | } | ||
819 | 837 | ||
820 | len += msg->text_len; | 838 | if (buf) { |
821 | len++; | 839 | if (print_prefix(msg, syslog, NULL) + |
822 | return len; | 840 | text_len + 1>= size - len) |
823 | } | 841 | break; |
842 | |||
843 | len += print_prefix(msg, syslog, buf + len); | ||
844 | memcpy(buf + len, text, text_len); | ||
845 | len += text_len; | ||
846 | buf[len++] = '\n'; | ||
847 | } else { | ||
848 | /* SYSLOG_ACTION_* buffer size only calculation */ | ||
849 | len += print_prefix(msg, syslog, NULL); | ||
850 | len += text_len + 1; | ||
851 | } | ||
852 | |||
853 | text = next; | ||
854 | } while (text); | ||
824 | 855 | ||
825 | len = sprintf(text, "<%u>", msg->level); | ||
826 | len += prepend_timestamp(msg->ts_nsec, text + len); | ||
827 | if (len + msg->text_len > size) | ||
828 | return -EINVAL; | ||
829 | memcpy(text + len, log_text(msg), msg->text_len); | ||
830 | len += msg->text_len; | ||
831 | text[len++] = '\n'; | ||
832 | return len; | 856 | return len; |
833 | } | 857 | } |
834 | 858 | ||
835 | static int syslog_print(char __user *buf, int size) | 859 | static int syslog_print(char __user *buf, int size) |
836 | { | 860 | { |
837 | char *text; | 861 | char *text; |
862 | struct log *msg; | ||
838 | int len; | 863 | int len; |
839 | 864 | ||
840 | text = kmalloc(LOG_LINE_MAX, GFP_KERNEL); | 865 | text = kmalloc(LOG_LINE_MAX, GFP_KERNEL); |
@@ -847,7 +872,8 @@ static int syslog_print(char __user *buf, int size) | |||
847 | syslog_seq = log_first_seq; | 872 | syslog_seq = log_first_seq; |
848 | syslog_idx = log_first_idx; | 873 | syslog_idx = log_first_idx; |
849 | } | 874 | } |
850 | len = syslog_print_line(syslog_idx, text, LOG_LINE_MAX); | 875 | msg = log_from_idx(syslog_idx); |
876 | len = msg_print_text(msg, true, text, LOG_LINE_MAX); | ||
851 | syslog_idx = log_next(syslog_idx); | 877 | syslog_idx = log_next(syslog_idx); |
852 | syslog_seq++; | 878 | syslog_seq++; |
853 | raw_spin_unlock_irq(&logbuf_lock); | 879 | raw_spin_unlock_irq(&logbuf_lock); |
@@ -887,14 +913,18 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
887 | seq = clear_seq; | 913 | seq = clear_seq; |
888 | idx = clear_idx; | 914 | idx = clear_idx; |
889 | while (seq < log_next_seq) { | 915 | while (seq < log_next_seq) { |
890 | len += syslog_print_line(idx, NULL, 0); | 916 | struct log *msg = log_from_idx(idx); |
917 | |||
918 | len += msg_print_text(msg, true, NULL, 0); | ||
891 | idx = log_next(idx); | 919 | idx = log_next(idx); |
892 | seq++; | 920 | seq++; |
893 | } | 921 | } |
894 | seq = clear_seq; | 922 | seq = clear_seq; |
895 | idx = clear_idx; | 923 | idx = clear_idx; |
896 | while (len > size && seq < log_next_seq) { | 924 | while (len > size && seq < log_next_seq) { |
897 | len -= syslog_print_line(idx, NULL, 0); | 925 | struct log *msg = log_from_idx(idx); |
926 | |||
927 | len -= msg_print_text(msg, true, NULL, 0); | ||
898 | idx = log_next(idx); | 928 | idx = log_next(idx); |
899 | seq++; | 929 | seq++; |
900 | } | 930 | } |
@@ -904,9 +934,10 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
904 | 934 | ||
905 | len = 0; | 935 | len = 0; |
906 | while (len >= 0 && seq < next_seq) { | 936 | while (len >= 0 && seq < next_seq) { |
937 | struct log *msg = log_from_idx(idx); | ||
907 | int textlen; | 938 | int textlen; |
908 | 939 | ||
909 | textlen = syslog_print_line(idx, text, LOG_LINE_MAX); | 940 | textlen = msg_print_text(msg, true, text, LOG_LINE_MAX); |
910 | if (textlen < 0) { | 941 | if (textlen < 0) { |
911 | len = textlen; | 942 | len = textlen; |
912 | break; | 943 | break; |
@@ -1044,7 +1075,9 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
1044 | seq = syslog_seq; | 1075 | seq = syslog_seq; |
1045 | idx = syslog_idx; | 1076 | idx = syslog_idx; |
1046 | while (seq < log_next_seq) { | 1077 | while (seq < log_next_seq) { |
1047 | error += syslog_print_line(idx, NULL, 0); | 1078 | struct log *msg = log_from_idx(idx); |
1079 | |||
1080 | error += msg_print_text(msg, true, NULL, 0); | ||
1048 | idx = log_next(idx); | 1081 | idx = log_next(idx); |
1049 | seq++; | 1082 | seq++; |
1050 | } | 1083 | } |
@@ -1439,10 +1472,8 @@ static struct log *log_from_idx(u32 idx) { return NULL; } | |||
1439 | static u32 log_next(u32 idx) { return 0; } | 1472 | static u32 log_next(u32 idx) { return 0; } |
1440 | static char *log_text(const struct log *msg) { return NULL; } | 1473 | static char *log_text(const struct log *msg) { return NULL; } |
1441 | static void call_console_drivers(int level, const char *text, size_t len) {} | 1474 | static void call_console_drivers(int level, const char *text, size_t len) {} |
1442 | static size_t prepend_timestamp(unsigned long long t, char *buf) | 1475 | static size_t msg_print_text(const struct log *msg, bool syslog, |
1443 | { | 1476 | char *buf, size_t size) { return 0; } |
1444 | return 0; | ||
1445 | } | ||
1446 | 1477 | ||
1447 | #endif /* CONFIG_PRINTK */ | 1478 | #endif /* CONFIG_PRINTK */ |
1448 | 1479 | ||
@@ -1750,7 +1781,7 @@ again: | |||
1750 | for (;;) { | 1781 | for (;;) { |
1751 | struct log *msg; | 1782 | struct log *msg; |
1752 | static char text[LOG_LINE_MAX]; | 1783 | static char text[LOG_LINE_MAX]; |
1753 | size_t len, l; | 1784 | size_t len; |
1754 | int level; | 1785 | int level; |
1755 | 1786 | ||
1756 | raw_spin_lock_irqsave(&logbuf_lock, flags); | 1787 | raw_spin_lock_irqsave(&logbuf_lock, flags); |
@@ -1771,13 +1802,7 @@ again: | |||
1771 | msg = log_from_idx(console_idx); | 1802 | msg = log_from_idx(console_idx); |
1772 | level = msg->level & 7; | 1803 | level = msg->level & 7; |
1773 | 1804 | ||
1774 | len = prepend_timestamp(msg->ts_nsec, text); | 1805 | len = msg_print_text(msg, false, text, sizeof(text)); |
1775 | l = msg->text_len; | ||
1776 | if (len + l + 1 >= sizeof(text)) | ||
1777 | l = sizeof(text) - len - 1; | ||
1778 | memcpy(text + len, log_text(msg), l); | ||
1779 | len += l; | ||
1780 | text[len++] = '\n'; | ||
1781 | 1806 | ||
1782 | console_idx = log_next(console_idx); | 1807 | console_idx = log_next(console_idx); |
1783 | console_seq++; | 1808 | console_seq++; |