aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/printk.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-16 18:05:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-16 18:05:40 -0400
commita5e6b135bdff649e4330f98e2e80dbb1984f7e77 (patch)
tree475bfb1163c59d1370fd77415255afba768f9520 /kernel/printk.c
parent971f115a50afbe409825c9f3399d5a3b9aca4381 (diff)
parent9d90c8d9cde929cbc575098e825d7c29d9f45054 (diff)
Merge branch 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (50 commits) printk: do not mangle valid userspace syslog prefixes efivars: Add Documentation efivars: Expose efivars functionality to external drivers. efivars: Parameterize operations. efivars: Split out variable registration efivars: parameterize efivars efivars: Make efivars bin_attributes dynamic efivars: move efivars globals into struct efivars drivers:misc: ti-st: fix debugging code kref: Fix typo in kref documentation UIO: add PRUSS UIO driver support Fix spelling mistakes in Documentation/zh_CN/SubmittingPatches firmware: Fix unaligned memory accesses in dmi-sysfs firmware: Add documentation for /sys/firmware/dmi firmware: Expose DMI type 15 System Event Log firmware: Break out system_event_log in dmi-sysfs firmware: Basic dmi-sysfs support firmware: Add DMI entry types to the headers Driver core: convert platform_{get,set}_drvdata to static inline functions Translate linux-2.6/Documentation/magic-number.txt into Chinese ...
Diffstat (limited to 'kernel/printk.c')
-rw-r--r--kernel/printk.c138
1 files changed, 104 insertions, 34 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index 36231525e22f..33284adb2189 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -515,6 +515,71 @@ static void _call_console_drivers(unsigned start,
515} 515}
516 516
517/* 517/*
518 * Parse the syslog header <[0-9]*>. The decimal value represents 32bit, the
519 * lower 3 bit are the log level, the rest are the log facility. In case
520 * userspace passes usual userspace syslog messages to /dev/kmsg or
521 * /dev/ttyprintk, the log prefix might contain the facility. Printk needs
522 * to extract the correct log level for in-kernel processing, and not mangle
523 * the original value.
524 *
525 * If a prefix is found, the length of the prefix is returned. If 'level' is
526 * passed, it will be filled in with the log level without a possible facility
527 * value. If 'special' is passed, the special printk prefix chars are accepted
528 * and returned. If no valid header is found, 0 is returned and the passed
529 * variables are not touched.
530 */
531static size_t log_prefix(const char *p, unsigned int *level, char *special)
532{
533 unsigned int lev = 0;
534 char sp = '\0';
535 size_t len;
536
537 if (p[0] != '<' || !p[1])
538 return 0;
539 if (p[2] == '>') {
540 /* usual single digit level number or special char */
541 switch (p[1]) {
542 case '0' ... '7':
543 lev = p[1] - '0';
544 break;
545 case 'c': /* KERN_CONT */
546 case 'd': /* KERN_DEFAULT */
547 sp = p[1];
548 break;
549 default:
550 return 0;
551 }
552 len = 3;
553 } else {
554 /* multi digit including the level and facility number */
555 char *endp = NULL;
556
557 if (p[1] < '0' && p[1] > '9')
558 return 0;
559
560 lev = (simple_strtoul(&p[1], &endp, 10) & 7);
561 if (endp == NULL || endp[0] != '>')
562 return 0;
563 len = (endp + 1) - p;
564 }
565
566 /* do not accept special char if not asked for */
567 if (sp && !special)
568 return 0;
569
570 if (special) {
571 *special = sp;
572 /* return special char, do not touch level */
573 if (sp)
574 return len;
575 }
576
577 if (level)
578 *level = lev;
579 return len;
580}
581
582/*
518 * Call the console drivers, asking them to write out 583 * Call the console drivers, asking them to write out
519 * log_buf[start] to log_buf[end - 1]. 584 * log_buf[start] to log_buf[end - 1].
520 * The console_lock must be held. 585 * The console_lock must be held.
@@ -529,13 +594,9 @@ static void call_console_drivers(unsigned start, unsigned end)
529 cur_index = start; 594 cur_index = start;
530 start_print = start; 595 start_print = start;
531 while (cur_index != end) { 596 while (cur_index != end) {
532 if (msg_level < 0 && ((end - cur_index) > 2) && 597 if (msg_level < 0 && ((end - cur_index) > 2)) {
533 LOG_BUF(cur_index + 0) == '<' && 598 /* strip log prefix */
534 LOG_BUF(cur_index + 1) >= '0' && 599 cur_index += log_prefix(&LOG_BUF(cur_index), &msg_level, NULL);
535 LOG_BUF(cur_index + 1) <= '7' &&
536 LOG_BUF(cur_index + 2) == '>') {
537 msg_level = LOG_BUF(cur_index + 1) - '0';
538 cur_index += 3;
539 start_print = cur_index; 600 start_print = cur_index;
540 } 601 }
541 while (cur_index != end) { 602 while (cur_index != end) {
@@ -733,6 +794,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
733 unsigned long flags; 794 unsigned long flags;
734 int this_cpu; 795 int this_cpu;
735 char *p; 796 char *p;
797 size_t plen;
798 char special;
736 799
737 boot_delay_msec(); 800 boot_delay_msec();
738 printk_delay(); 801 printk_delay();
@@ -773,45 +836,52 @@ asmlinkage int vprintk(const char *fmt, va_list args)
773 printed_len += vscnprintf(printk_buf + printed_len, 836 printed_len += vscnprintf(printk_buf + printed_len,
774 sizeof(printk_buf) - printed_len, fmt, args); 837 sizeof(printk_buf) - printed_len, fmt, args);
775 838
776
777 p = printk_buf; 839 p = printk_buf;
778 840
779 /* Do we have a loglevel in the string? */ 841 /* Read log level and handle special printk prefix */
780 if (p[0] == '<') { 842 plen = log_prefix(p, &current_log_level, &special);
781 unsigned char c = p[1]; 843 if (plen) {
782 if (c && p[2] == '>') { 844 p += plen;
783 switch (c) { 845
784 case '0' ... '7': /* loglevel */ 846 switch (special) {
785 current_log_level = c - '0'; 847 case 'c': /* Strip <c> KERN_CONT, continue line */
786 /* Fallthrough - make sure we're on a new line */ 848 plen = 0;
787 case 'd': /* KERN_DEFAULT */ 849 break;
788 if (!new_text_line) { 850 case 'd': /* Strip <d> KERN_DEFAULT, start new line */
789 emit_log_char('\n'); 851 plen = 0;
790 new_text_line = 1; 852 default:
791 } 853 if (!new_text_line) {
792 /* Fallthrough - skip the loglevel */ 854 emit_log_char('\n');
793 case 'c': /* KERN_CONT */ 855 new_text_line = 1;
794 p += 3;
795 break;
796 } 856 }
797 } 857 }
798 } 858 }
799 859
800 /* 860 /*
801 * Copy the output into log_buf. If the caller didn't provide 861 * Copy the output into log_buf. If the caller didn't provide
802 * appropriate log level tags, we insert them here 862 * the appropriate log prefix, we insert them here
803 */ 863 */
804 for ( ; *p; p++) { 864 for (; *p; p++) {
805 if (new_text_line) { 865 if (new_text_line) {
806 /* Always output the token */
807 emit_log_char('<');
808 emit_log_char(current_log_level + '0');
809 emit_log_char('>');
810 printed_len += 3;
811 new_text_line = 0; 866 new_text_line = 0;
812 867
868 if (plen) {
869 /* Copy original log prefix */
870 int i;
871
872 for (i = 0; i < plen; i++)
873 emit_log_char(printk_buf[i]);
874 printed_len += plen;
875 } else {
876 /* Add log prefix */
877 emit_log_char('<');
878 emit_log_char(current_log_level + '0');
879 emit_log_char('>');
880 printed_len += 3;
881 }
882
813 if (printk_time) { 883 if (printk_time) {
814 /* Follow the token with the time */ 884 /* Add the current time stamp */
815 char tbuf[50], *tp; 885 char tbuf[50], *tp;
816 unsigned tlen; 886 unsigned tlen;
817 unsigned long long t; 887 unsigned long long t;