1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/kernel.h>
20#include <linux/mm.h>
21#include <linux/tty.h>
22#include <linux/tty_driver.h>
23#include <linux/smp_lock.h>
24#include <linux/console.h>
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/interrupt.h>
28#include <linux/config.h>
29#include <linux/delay.h>
30#include <linux/smp.h>
31#include <linux/security.h>
32#include <linux/bootmem.h>
33#include <linux/syscalls.h>
34
35#include <asm/uaccess.h>
36
37#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
38
39
40#define DEFAULT_MESSAGE_LOGLEVEL 4
41
42
43#define MINIMUM_CONSOLE_LOGLEVEL 1
44#define DEFAULT_CONSOLE_LOGLEVEL 7
45
46DECLARE_WAIT_QUEUE_HEAD(log_wait);
47
48int console_printk[4] = {
49 DEFAULT_CONSOLE_LOGLEVEL,
50 DEFAULT_MESSAGE_LOGLEVEL,
51 MINIMUM_CONSOLE_LOGLEVEL,
52 DEFAULT_CONSOLE_LOGLEVEL,
53};
54
55EXPORT_SYMBOL(console_printk);
56
57int oops_in_progress;
58
59
60
61
62
63
64static DECLARE_MUTEX(console_sem);
65struct console *console_drivers;
66
67
68
69
70
71
72
73
74static int console_locked;
75
76
77
78
79
80
81static DEFINE_SPINLOCK(logbuf_lock);
82
83static char __log_buf[__LOG_BUF_LEN];
84static char *log_buf = __log_buf;
85static int log_buf_len = __LOG_BUF_LEN;
86
87#define LOG_BUF_MASK (log_buf_len-1)
88#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
89
90
91
92
93
94static unsigned long log_start;
95static unsigned long con_start;
96static unsigned long log_end;
97static unsigned long logged_chars;
98
99
100
101
102struct console_cmdline
103{
104 char name[8];
105 int index;
106 char *options;
107};
108
109#define MAX_CMDLINECONSOLES 8
110
111static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
112static int selected_console = -1;
113static int preferred_console = -1;
114
115
116static int console_may_schedule;
117
118
119
120
121static int __init console_setup(char *str)
122{
123 char name[sizeof(console_cmdline[0].name)];
124 char *s, *options;
125 int idx;
126
127
128
129
130 if (str[0] >= '0' && str[0] <= '9') {
131 strcpy(name, "ttyS");
132 strncpy(name + 4, str, sizeof(name) - 5);
133 } else
134 strncpy(name, str, sizeof(name) - 1);
135 name[sizeof(name) - 1] = 0;
136 if ((options = strchr(str, ',')) != NULL)
137 *(options++) = 0;
138#ifdef __sparc__
139 if (!strcmp(str, "ttya"))
140 strcpy(name, "ttyS0");
141 if (!strcmp(str, "ttyb"))
142 strcpy(name, "ttyS1");
143#endif
144 for(s = name; *s; s++)
145 if ((*s >= '0' && *s <= '9') || *s == ',')
146 break;
147 idx = simple_strtoul(s, NULL, 10);
148 *s = 0;
149
150 add_preferred_console(name, idx, options);
151 return 1;
152}
153
154__setup("console=", console_setup);
155
156
157
158
159
160
161
162
163
164
165
166int __init add_preferred_console(char *name, int idx, char *options)
167{
168 struct console_cmdline *c;
169 int i;
170
171
172
173
174
175 for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
176 if (strcmp(console_cmdline[i].name, name) == 0 &&
177 console_cmdline[i].index == idx) {
178 selected_console = i;
179 return 0;
180 }
181 if (i == MAX_CMDLINECONSOLES)
182 return -E2BIG;
183 selected_console = i;
184 c = &console_cmdline[i];
185 memcpy(c->name, name, sizeof(c->name));
186 c->name[sizeof(c->name) - 1] = 0;
187 c->options = options;
188 c->index = idx;
189 return 0;
190}
191
192static int __init log_buf_len_setup(char *str)
193{
194 unsigned long size = memparse(str, &str);
195 unsigned long flags;
196
197 if (size)
198 size = roundup_pow_of_two(size);
199 if (size > log_buf_len) {
200 unsigned long start, dest_idx, offset;
201 char * new_log_buf;
202
203 new_log_buf = alloc_bootmem(size);
204 if (!new_log_buf) {
205 printk("log_buf_len: allocation failed\n");
206 goto out;
207 }
208
209 spin_lock_irqsave(&logbuf_lock, flags);
210 log_buf_len = size;
211 log_buf = new_log_buf;
212
213 offset = start = min(con_start, log_start);
214 dest_idx = 0;
215 while (start != log_end) {
216 log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
217 start++;
218 dest_idx++;
219 }
220 log_start -= offset;
221 con_start -= offset;
222 log_end -= offset;
223 spin_unlock_irqrestore(&logbuf_lock, flags);
224
225 printk("log_buf_len: %d\n", log_buf_len);
226 }
227out:
228
229 return 1;
230}
231
232__setup("log_buf_len=", log_buf_len_setup);
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249int do_syslog(int type, char __user * buf, int len)
250{
251 unsigned long i, j, limit, count;
252 int do_clear = 0;
253 char c;
254 int error = 0;
255
256 error = security_syslog(type);
257 if (error)
258 return error;
259
260 switch (type) {
261 case 0:
262 break;
263 case 1:
264 break;
265 case 2:
266 error = -EINVAL;
267 if (!buf || len < 0)
268 goto out;
269 error = 0;
270 if (!len)
271 goto out;
272 error = verify_area(VERIFY_WRITE,buf,len);
273 if (error)
274 goto out;
275 error = wait_event_interruptible(log_wait, (log_start - log_end));
276 if (error)
277 goto out;
278 i = 0;
279 spin_lock_irq(&logbuf_lock);
280 while (!error && (log_start != log_end) && i < len) {
281 c = LOG_BUF(log_start);
282 log_start++;
283 spin_unlock_irq(&logbuf_lock);
284 error = __put_user(c,buf);
285 buf++;
286 i++;
287 cond_resched();
288 spin_lock_irq(&logbuf_lock);
289 }
290 spin_unlock_irq(&logbuf_lock);
291 if (!error)
292 error = i;
293 break;
294 case 4:
295 do_clear = 1;
296
297 case 3:
298 error = -EINVAL;
299 if (!buf || len < 0)
300 goto out;
301 error = 0;
302 if (!len)
303 goto out;
304 error = verify_area(VERIFY_WRITE,buf,len);
305 if (error)
306 goto out;
307 count = len;
308 if (count > log_buf_len)
309 count = log_buf_len;
310 spin_lock_irq(&logbuf_lock);
311 if (count > logged_chars)
312 count = logged_chars;
313 if (do_clear)
314 logged_chars = 0;
315 limit = log_end;
316
317
318
319
320
321
322 for(i = 0; i < count && !error; i++) {
323 j = limit-1-i;
324 if (j + log_buf_len < log_end)
325 break;
326 c = LOG_BUF(j);
327 spin_unlock_irq(&logbuf_lock);
328 error = __put_user(c,&buf[count-1-i]);
329 cond_resched();
330 spin_lock_irq(&logbuf_lock);
331 }
332 spin_unlock_irq(&logbuf_lock);
333 if (error)
334 break;
335 error = i;
336 if(i != count) {
337 int offset = count-error;
338
339 for(i=0;i<error;i++) {
340 if (__get_user(c,&buf[i+offset]) ||
341 __put_user(c,&buf[i])) {
342 error = -EFAULT;
343 break;
344 }
345 cond_resched();
346 }
347 }
348 break;
349 case 5:
350 logged_chars = 0;
351 break;
352 case 6:
353 console_loglevel = minimum_console_loglevel;
354 break;
355 case 7:
356 console_loglevel = default_console_loglevel;
357 break;
358 case 8:
359 error = -EINVAL;
360 if (len < 1 || len > 8)
361 goto out;
362 if (len < minimum_console_loglevel)
363 len = minimum_console_loglevel;
364 console_loglevel = len;
365 error = 0;
366 break;
367 case 9:
368 error = log_end - log_start;
369 break;
370 case 10:
371 error = log_buf_len;
372 break;
373 default:
374 error = -EINVAL;
375 break;
376 }
377out:
378 return error;
379}
380
381asmlinkage long sys_syslog(int type, char __user * buf, int len)
382{
383 return do_syslog(type, buf, len);
384}
385
386
387
388
389static void __call_console_drivers(unsigned long start, unsigned long end)
390{
391 struct console *con;
392
393 for (con = console_drivers; con; con = con->next) {
394 if ((con->flags & CON_ENABLED) && con->write)
395 con->write(con, &LOG_BUF(start), end - start);
396 }
397}
398
399
400
401
402static void _call_console_drivers(unsigned long start,
403 unsigned long end, int msg_log_level)
404{
405 if (msg_log_level < console_loglevel &&
406 console_drivers && start != end) {
407 if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
408
409 __call_console_drivers(start & LOG_BUF_MASK,
410 log_buf_len);
411 __call_console_drivers(0, end & LOG_BUF_MASK);
412 } else {
413 __call_console_drivers(start, end);
414 }
415 }
416}
417
418
419
420
421
422
423static void call_console_drivers(unsigned long start, unsigned long end)
424{
425 unsigned long cur_index, start_print;
426 static int msg_level = -1;
427
428 if (((long)(start - end)) > 0)
429 BUG();
430
431 cur_index = start;
432 start_print = start;
433 while (cur_index != end) {
434 if ( msg_level < 0 &&
435 ((end - cur_index) > 2) &&
436 LOG_BUF(cur_index + 0) == '<' &&
437 LOG_BUF(cur_index + 1) >= '0' &&
438 LOG_BUF(cur_index + 1) <= '7' &&
439 LOG_BUF(cur_index + 2) == '>')
440 {
441 msg_level = LOG_BUF(cur_index + 1) - '0';
442 cur_index += 3;
443 start_print = cur_index;
444 }
445 while (cur_index != end) {
446 char c = LOG_BUF(cur_index);
447 cur_index++;
448
449 if (c == '\n') {
450 if (msg_level < 0) {
451
452
453
454
455
456
457 msg_level = default_message_loglevel;
458 }
459 _call_console_drivers(start_print, cur_index, msg_level);
460 msg_level = -1;
461 start_print = cur_index;
462 break;
463 }
464 }
465 }
466 _call_console_drivers(start_print, end, msg_level);
467}
468
469static void emit_log_char(char c)
470{
471 LOG_BUF(log_end) = c;
472 log_end++;
473 if (log_end - log_start > log_buf_len)
474 log_start = log_end - log_buf_len;
475 if (log_end - con_start > log_buf_len)
476 con_start = log_end - log_buf_len;
477 if (logged_chars < log_buf_len)
478 logged_chars++;
479}
480
481
482
483
484
485
486static void zap_locks(void)
487{
488 static unsigned long oops_timestamp;
489
490 if (time_after_eq(jiffies, oops_timestamp) &&
491 !time_after(jiffies, oops_timestamp + 30*HZ))
492 return;
493
494 oops_timestamp = jiffies;
495
496
497 spin_lock_init(&logbuf_lock);
498
499 init_MUTEX(&console_sem);
500}
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515asmlinkage int printk(const char *fmt, ...)
516{
517 va_list args;
518 int r;
519
520 va_start(args, fmt);
521 r = vprintk(fmt, args);
522 va_end(args);
523
524 return r;
525}
526
527asmlinkage int vprintk(const char *fmt, va_list args)
528{
529 unsigned long flags;
530 int printed_len;
531 char *p;
532 static char printk_buf[1024];
533 static int log_level_unknown = 1;
534
535 if (unlikely(oops_in_progress))
536 zap_locks();
537
538
539 spin_lock_irqsave(&logbuf_lock, flags);
540
541
542 printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
543
544
545
546
547
548 for (p = printk_buf; *p; p++) {
549 if (log_level_unknown) {
550 if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
551 emit_log_char('<');
552 emit_log_char(default_message_loglevel + '0');
553 emit_log_char('>');
554 }
555 log_level_unknown = 0;
556 }
557 emit_log_char(*p);
558 if (*p == '\n')
559 log_level_unknown = 1;
560 }
561
562 if (!cpu_online(smp_processor_id()) &&
563 system_state != SYSTEM_RUNNING) {
564
565
566
567
568
569
570 spin_unlock_irqrestore(&logbuf_lock, flags);
571 goto out;
572 }
573 if (!down_trylock(&console_sem)) {
574 console_locked = 1;
575
576
577
578
579 spin_unlock_irqrestore(&logbuf_lock, flags);
580 console_may_schedule = 0;
581 release_console_sem();
582 } else {
583
584
585
586
587
588 spin_unlock_irqrestore(&logbuf_lock, flags);
589 }
590out:
591 return printed_len;
592}
593EXPORT_SYMBOL(printk);
594EXPORT_SYMBOL(vprintk);
595
596
597
598
599
600
601
602
603
604void acquire_console_sem(void)
605{
606 if (in_interrupt())
607 BUG();
608 down(&console_sem);
609 console_locked = 1;
610 console_may_schedule = 1;
611}
612EXPORT_SYMBOL(acquire_console_sem);
613
614int try_acquire_console_sem(void)
615{
616 if (down_trylock(&console_sem))
617 return -1;
618 console_locked = 1;
619 console_may_schedule = 0;
620 return 0;
621}
622EXPORT_SYMBOL(try_acquire_console_sem);
623
624int is_console_locked(void)
625{
626 return console_locked;
627}
628EXPORT_SYMBOL(is_console_locked);
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644void release_console_sem(void)
645{
646 unsigned long flags;
647 unsigned long _con_start, _log_end;
648 unsigned long wake_klogd = 0;
649
650 for ( ; ; ) {
651 spin_lock_irqsave(&logbuf_lock, flags);
652 wake_klogd |= log_start - log_end;
653 if (con_start == log_end)
654 break;
655 _con_start = con_start;
656 _log_end = log_end;
657 con_start = log_end;
658 spin_unlock(&logbuf_lock);
659 call_console_drivers(_con_start, _log_end);
660 local_irq_restore(flags);
661 }
662 console_locked = 0;
663 console_may_schedule = 0;
664 up(&console_sem);
665 spin_unlock_irqrestore(&logbuf_lock, flags);
666 if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
667 wake_up_interruptible(&log_wait);
668}
669EXPORT_SYMBOL(release_console_sem);
670
671
672
673
674
675
676
677
678
679void __sched console_conditional_schedule(void)
680{
681 if (console_may_schedule)
682 cond_resched();
683}
684EXPORT_SYMBOL(console_conditional_schedule);
685
686void console_print(const char *s)
687{
688 printk(KERN_EMERG "%s", s);
689}
690EXPORT_SYMBOL(console_print);
691
692void console_unblank(void)
693{
694 struct console *c;
695
696
697
698
699
700
701 if (down_trylock(&console_sem) != 0)
702 return;
703 console_locked = 1;
704 console_may_schedule = 0;
705 for (c = console_drivers; c != NULL; c = c->next)
706 if ((c->flags & CON_ENABLED) && c->unblank)
707 c->unblank();
708 release_console_sem();
709}
710EXPORT_SYMBOL(console_unblank);
711
712
713
714
715struct tty_driver *console_device(int *index)
716{
717 struct console *c;
718 struct tty_driver *driver = NULL;
719
720 acquire_console_sem();
721 for (c = console_drivers; c != NULL; c = c->next) {
722 if (!c->device)
723 continue;
724 driver = c->device(c, index);
725 if (driver)
726 break;
727 }
728 release_console_sem();
729 return driver;
730}
731
732
733
734
735
736
737void console_stop(struct console *console)
738{
739 acquire_console_sem();
740 console->flags &= ~CON_ENABLED;
741 release_console_sem();
742}
743EXPORT_SYMBOL(console_stop);
744
745void console_start(struct console *console)
746{
747 acquire_console_sem();
748 console->flags |= CON_ENABLED;
749 release_console_sem();
750}
751EXPORT_SYMBOL(console_start);
752
753
754
755
756
757
758
759void register_console(struct console * console)
760{
761 int i;
762 unsigned long flags;
763
764 if (preferred_console < 0)
765 preferred_console = selected_console;
766
767
768
769
770
771
772 if (preferred_console < 0) {
773 if (console->index < 0)
774 console->index = 0;
775 if (console->setup == NULL ||
776 console->setup(console, NULL) == 0) {
777 console->flags |= CON_ENABLED | CON_CONSDEV;
778 preferred_console = 0;
779 }
780 }
781
782
783
784
785
786 for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
787 if (strcmp(console_cmdline[i].name, console->name) != 0)
788 continue;
789 if (console->index >= 0 &&
790 console->index != console_cmdline[i].index)
791 continue;
792 if (console->index < 0)
793 console->index = console_cmdline[i].index;
794 if (console->setup &&
795 console->setup(console, console_cmdline[i].options) != 0)
796 break;
797 console->flags |= CON_ENABLED;
798 console->index = console_cmdline[i].index;
799 if (i == preferred_console)
800 console->flags |= CON_CONSDEV;
801 break;
802 }
803
804 if (!(console->flags & CON_ENABLED))
805 return;
806
807
808
809
810
811 acquire_console_sem();
812 if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
813 console->next = console_drivers;
814 console_drivers = console;
815 } else {
816 console->next = console_drivers->next;
817 console_drivers->next = console;
818 }
819 if (console->flags & CON_PRINTBUFFER) {
820
821
822
823
824 spin_lock_irqsave(&logbuf_lock, flags);
825 con_start = log_start;
826 spin_unlock_irqrestore(&logbuf_lock, flags);
827 }
828 release_console_sem();
829}
830EXPORT_SYMBOL(register_console);
831
832int unregister_console(struct console * console)
833{
834 struct console *a,*b;
835 int res = 1;
836
837 acquire_console_sem();
838 if (console_drivers == console) {
839 console_drivers=console->next;
840 res = 0;
841 } else {
842 for (a=console_drivers->next, b=console_drivers ;
843 a; b=a, a=b->next) {
844 if (a == console) {
845 b->next = a->next;
846 res = 0;
847 break;
848 }
849 }
850 }
851
852
853
854
855
856 if (console_drivers == NULL)
857 preferred_console = selected_console;
858
859
860 release_console_sem();
861 return res;
862}
863EXPORT_SYMBOL(unregister_console);
864
865
866
867
868
869
870
871
872void tty_write_message(struct tty_struct *tty, char *msg)
873{
874 if (tty && tty->driver->write)
875 tty->driver->write(tty, msg, strlen(msg));
876 return;
877}
878
879
880
881
882
883
884
885
886int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
887{
888 static DEFINE_SPINLOCK(ratelimit_lock);
889 static unsigned long toks = 10*5*HZ;
890 static unsigned long last_msg;
891 static int missed;
892 unsigned long flags;
893 unsigned long now = jiffies;
894
895 spin_lock_irqsave(&ratelimit_lock, flags);
896 toks += now - last_msg;
897 last_msg = now;
898 if (toks > (ratelimit_burst * ratelimit_jiffies))
899 toks = ratelimit_burst * ratelimit_jiffies;
900 if (toks >= ratelimit_jiffies) {
901 int lost = missed;
902 missed = 0;
903 toks -= ratelimit_jiffies;
904 spin_unlock_irqrestore(&ratelimit_lock, flags);
905 if (lost)
906 printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
907 return 1;
908 }
909 missed++;
910 spin_unlock_irqrestore(&ratelimit_lock, flags);
911 return 0;
912}
913EXPORT_SYMBOL(__printk_ratelimit);
914
915
916int printk_ratelimit_jiffies = 5*HZ;
917
918
919int printk_ratelimit_burst = 10;
920
921int printk_ratelimit(void)
922{
923 return __printk_ratelimit(printk_ratelimit_jiffies,
924 printk_ratelimit_burst);
925}
926EXPORT_SYMBOL(printk_ratelimit);
927