1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/mm.h>
20#include <linux/tty.h>
21#include <linux/tty_driver.h>
22#include <linux/smp_lock.h>
23#include <linux/console.h>
24#include <linux/init.h>
25#include <linux/module.h>
26#include <linux/interrupt.h>
27#include <linux/config.h>
28#include <linux/slab.h>
29#include <linux/delay.h>
30
31#include <asm/uaccess.h>
32
33#if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64)
34#define LOG_BUF_LEN (65536)
35#elif defined(CONFIG_ARCH_S390)
36#define LOG_BUF_LEN (131072)
37#elif defined(CONFIG_SMP)
38#define LOG_BUF_LEN (32768)
39#else
40#define LOG_BUF_LEN (16384)
41#endif
42
43#define LOG_BUF_MASK (LOG_BUF_LEN-1)
44
45#ifndef arch_consoles_callable
46#define arch_consoles_callable() (1)
47#endif
48
49
50#define DEFAULT_MESSAGE_LOGLEVEL 4
51
52
53#define MINIMUM_CONSOLE_LOGLEVEL 1
54#define DEFAULT_CONSOLE_LOGLEVEL 7
55
56DECLARE_WAIT_QUEUE_HEAD(log_wait);
57
58
59int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
60int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
61int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
62int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
63
64int oops_in_progress;
65
66
67
68
69
70
71static DECLARE_MUTEX(console_sem);
72struct console *console_drivers;
73
74
75
76
77
78
79static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED;
80
81static char log_buf[LOG_BUF_LEN];
82#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
83
84
85
86
87
88static unsigned long log_start;
89static unsigned long con_start;
90static unsigned long log_end;
91static unsigned long logged_chars;
92
93struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
94static int preferred_console = -1;
95
96
97static int console_may_schedule;
98
99
100
101
102static int __init console_setup(char *str)
103{
104 struct console_cmdline *c;
105 char name[sizeof(c->name)];
106 char *s, *options;
107 int i, idx;
108
109
110
111
112 if (str[0] >= '0' && str[0] <= '9') {
113 strcpy(name, "ttyS");
114 strncpy(name + 4, str, sizeof(name) - 5);
115 } else
116 strncpy(name, str, sizeof(name) - 1);
117 name[sizeof(name) - 1] = 0;
118 if ((options = strchr(str, ',')) != NULL)
119 *(options++) = 0;
120#ifdef __sparc__
121 if (!strcmp(str, "ttya"))
122 strcpy(name, "ttyS0");
123 if (!strcmp(str, "ttyb"))
124 strcpy(name, "ttyS1");
125#endif
126 for(s = name; *s; s++)
127 if (*s >= '0' && *s <= '9')
128 break;
129 idx = simple_strtoul(s, NULL, 10);
130 *s = 0;
131
132
133
134
135
136 for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
137 if (strcmp(console_cmdline[i].name, name) == 0 &&
138 console_cmdline[i].index == idx) {
139 preferred_console = i;
140 return 1;
141 }
142 if (i == MAX_CMDLINECONSOLES)
143 return 1;
144 preferred_console = i;
145 c = &console_cmdline[i];
146 memcpy(c->name, name, sizeof(c->name));
147 c->options = options;
148 c->index = idx;
149 return 1;
150}
151
152__setup("console=", console_setup);
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170int do_syslog(int type, char * buf, int len)
171{
172 unsigned long i, j, limit, count;
173 int do_clear = 0;
174 char c;
175 char *lbuf = NULL;
176 int error = 0;
177
178 switch (type) {
179 case 0:
180 break;
181 case 1:
182 break;
183 case 2:
184 error = -EINVAL;
185 if (!buf || len < 0)
186 goto out;
187 error = 0;
188 if (!len)
189 goto out;
190 error = verify_area(VERIFY_WRITE,buf,len);
191 if (error)
192 goto out;
193 error = wait_event_interruptible(log_wait, (log_start - log_end));
194 if (error)
195 goto out;
196 i = 0;
197 spin_lock_irq(&logbuf_lock);
198 while ((log_start != log_end) && i < len) {
199 c = LOG_BUF(log_start);
200 log_start++;
201 spin_unlock_irq(&logbuf_lock);
202 __put_user(c,buf);
203 buf++;
204 i++;
205 spin_lock_irq(&logbuf_lock);
206 }
207 spin_unlock_irq(&logbuf_lock);
208 error = i;
209 break;
210 case 4:
211 do_clear = 1;
212
213 case 3:
214 error = -EINVAL;
215 if (!buf || len < 0)
216 goto out;
217 error = 0;
218 if (!len)
219 goto out;
220 error = verify_area(VERIFY_WRITE,buf,len);
221 if (error)
222 goto out;
223 count = len;
224 if (count > LOG_BUF_LEN)
225 count = LOG_BUF_LEN;
226 spin_lock_irq(&logbuf_lock);
227 if (count > logged_chars)
228 count = logged_chars;
229 if (do_clear)
230 logged_chars = 0;
231 limit = log_end;
232
233
234
235
236
237
238 for(i=0;i < count;i++) {
239 j = limit-1-i;
240 if (j+LOG_BUF_LEN < log_end)
241 break;
242 c = LOG_BUF(j);
243 spin_unlock_irq(&logbuf_lock);
244 __put_user(c,&buf[count-1-i]);
245 spin_lock_irq(&logbuf_lock);
246 }
247 spin_unlock_irq(&logbuf_lock);
248 error = i;
249 if(i != count) {
250 int offset = count-error;
251
252 for(i=0;i<error;i++) {
253 __get_user(c,&buf[i+offset]);
254 __put_user(c,&buf[i]);
255 }
256 }
257
258 break;
259 case 5:
260 spin_lock_irq(&logbuf_lock);
261 logged_chars = 0;
262 spin_unlock_irq(&logbuf_lock);
263 break;
264 case 6:
265 spin_lock_irq(&logbuf_lock);
266 console_loglevel = minimum_console_loglevel;
267 spin_unlock_irq(&logbuf_lock);
268 break;
269 case 7:
270 spin_lock_irq(&logbuf_lock);
271 console_loglevel = default_console_loglevel;
272 spin_unlock_irq(&logbuf_lock);
273 break;
274 case 8:
275 error = -EINVAL;
276 if (len < 1 || len > 8)
277 goto out;
278 if (len < minimum_console_loglevel)
279 len = minimum_console_loglevel;
280 spin_lock_irq(&logbuf_lock);
281 console_loglevel = len;
282 spin_unlock_irq(&logbuf_lock);
283 error = 0;
284 break;
285 case 9:
286 spin_lock_irq(&logbuf_lock);
287 error = log_end - log_start;
288 spin_unlock_irq(&logbuf_lock);
289 break;
290 case 10:
291 lbuf = kmalloc(len + 1, GFP_KERNEL);
292 error = -ENOMEM;
293 if (lbuf == NULL)
294 break;
295 error = -EFAULT;
296 if (copy_from_user(lbuf, buf, len))
297 break;
298 lbuf[len] = '\0';
299 error = printk("%s", lbuf);
300 break;
301 default:
302 error = -EINVAL;
303 break;
304 }
305out:
306 kfree(lbuf);
307 return error;
308}
309
310asmlinkage long sys_syslog(int type, char * buf, int len)
311{
312 if ((type != 3) && !capable(CAP_SYS_ADMIN))
313 return -EPERM;
314 return do_syslog(type, buf, len);
315}
316
317
318
319
320static void __call_console_drivers(unsigned long start, unsigned long end)
321{
322 struct console *con;
323
324 for (con = console_drivers; con; con = con->next) {
325 if ((con->flags & CON_ENABLED) && con->write)
326 con->write(con, &LOG_BUF(start), end - start);
327 }
328}
329
330
331
332
333static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level)
334{
335 if (msg_log_level < console_loglevel && console_drivers && start != end) {
336 if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
337
338 __call_console_drivers(start & LOG_BUF_MASK, LOG_BUF_LEN);
339 __call_console_drivers(0, end & LOG_BUF_MASK);
340 } else {
341 __call_console_drivers(start, end);
342 }
343 }
344}
345
346
347
348
349
350
351static void call_console_drivers(unsigned long start, unsigned long end)
352{
353 unsigned long cur_index, start_print;
354 static int msg_level = -1;
355
356 if (((long)(start - end)) > 0)
357 BUG();
358
359 cur_index = start;
360 start_print = start;
361 while (cur_index != end) {
362 if ( msg_level < 0 &&
363 ((end - cur_index) > 2) &&
364 LOG_BUF(cur_index + 0) == '<' &&
365 LOG_BUF(cur_index + 1) >= '0' &&
366 LOG_BUF(cur_index + 1) <= '7' &&
367 LOG_BUF(cur_index + 2) == '>')
368 {
369 msg_level = LOG_BUF(cur_index + 1) - '0';
370 cur_index += 3;
371 start_print = cur_index;
372 }
373 while (cur_index != end) {
374 char c = LOG_BUF(cur_index);
375 cur_index++;
376
377 if (c == '\n') {
378 if (msg_level < 0) {
379
380
381
382
383
384
385 msg_level = default_message_loglevel;
386 }
387 _call_console_drivers(start_print, cur_index, msg_level);
388 msg_level = -1;
389 start_print = cur_index;
390 break;
391 }
392 }
393 }
394 _call_console_drivers(start_print, end, msg_level);
395}
396
397static void emit_log_char(char c)
398{
399 LOG_BUF(log_end) = c;
400 log_end++;
401 if (log_end - log_start > LOG_BUF_LEN)
402 log_start = log_end - LOG_BUF_LEN;
403 if (log_end - con_start > LOG_BUF_LEN)
404 con_start = log_end - LOG_BUF_LEN;
405 if (logged_chars < LOG_BUF_LEN)
406 logged_chars++;
407}
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422asmlinkage int printk(const char *fmt, ...)
423{
424 va_list args;
425 unsigned long flags;
426 int printed_len;
427 char *p;
428 static char printk_buf[1024];
429 static int log_level_unknown = 1;
430
431 if (oops_in_progress) {
432
433 spin_lock_init(&logbuf_lock);
434
435 init_MUTEX(&console_sem);
436 }
437
438
439 spin_lock_irqsave(&logbuf_lock, flags);
440
441
442 va_start(args, fmt);
443 printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
444 va_end(args);
445
446
447
448
449
450 for (p = printk_buf; *p; p++) {
451 if (log_level_unknown) {
452 if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
453 emit_log_char('<');
454 emit_log_char(default_message_loglevel + '0');
455 emit_log_char('>');
456 }
457 log_level_unknown = 0;
458 }
459 emit_log_char(*p);
460 if (*p == '\n')
461 log_level_unknown = 1;
462 }
463
464 if (!arch_consoles_callable()) {
465
466
467
468
469 spin_unlock_irqrestore(&logbuf_lock, flags);
470 goto out;
471 }
472 if (!down_trylock(&console_sem)) {
473
474
475
476
477 spin_unlock_irqrestore(&logbuf_lock, flags);
478 console_may_schedule = 0;
479 release_console_sem();
480 } else {
481
482
483
484
485
486 spin_unlock_irqrestore(&logbuf_lock, flags);
487 }
488out:
489 return printed_len;
490}
491EXPORT_SYMBOL(printk);
492
493
494
495
496
497
498
499
500
501void acquire_console_sem(void)
502{
503 if (in_interrupt())
504 BUG();
505 down(&console_sem);
506 console_may_schedule = 1;
507}
508EXPORT_SYMBOL(acquire_console_sem);
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524void release_console_sem(void)
525{
526 unsigned long flags;
527 unsigned long _con_start, _log_end;
528 unsigned long wake_klogd = 0;
529
530 for ( ; ; ) {
531 spin_lock_irqsave(&logbuf_lock, flags);
532 wake_klogd |= log_start - log_end;
533 if (con_start == log_end)
534 break;
535 _con_start = con_start;
536 _log_end = log_end;
537 con_start = log_end;
538 spin_unlock_irqrestore(&logbuf_lock, flags);
539 call_console_drivers(_con_start, _log_end);
540 }
541 console_may_schedule = 0;
542 up(&console_sem);
543 spin_unlock_irqrestore(&logbuf_lock, flags);
544 if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
545 wake_up_interruptible(&log_wait);
546}
547
548
549
550
551
552
553
554
555
556void console_conditional_schedule(void)
557{
558 if (console_may_schedule && need_resched()) {
559 set_current_state(TASK_RUNNING);
560 schedule();
561 }
562}
563
564void console_print(const char *s)
565{
566 printk(KERN_EMERG "%s", s);
567}
568EXPORT_SYMBOL(console_print);
569
570void console_unblank(void)
571{
572 struct console *c;
573
574
575
576
577
578
579 if (down_trylock(&console_sem) != 0)
580 return;
581 console_may_schedule = 0;
582 for (c = console_drivers; c != NULL; c = c->next)
583 if ((c->flags & CON_ENABLED) && c->unblank)
584 c->unblank();
585 release_console_sem();
586}
587EXPORT_SYMBOL(console_unblank);
588
589
590
591
592
593
594
595void register_console(struct console * console)
596{
597 int i;
598 unsigned long flags;
599
600
601
602
603
604
605 if (preferred_console < 0) {
606 if (console->index < 0)
607 console->index = 0;
608 if (console->setup == NULL ||
609 console->setup(console, NULL) == 0) {
610 console->flags |= CON_ENABLED | CON_CONSDEV;
611 preferred_console = 0;
612 }
613 }
614
615
616
617
618
619 for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
620 if (strcmp(console_cmdline[i].name, console->name) != 0)
621 continue;
622 if (console->index >= 0 &&
623 console->index != console_cmdline[i].index)
624 continue;
625 if (console->index < 0)
626 console->index = console_cmdline[i].index;
627 if (console->setup &&
628 console->setup(console, console_cmdline[i].options) != 0)
629 break;
630 console->flags |= CON_ENABLED;
631 console->index = console_cmdline[i].index;
632 if (i == preferred_console)
633 console->flags |= CON_CONSDEV;
634 break;
635 }
636
637 if (!(console->flags & CON_ENABLED))
638 return;
639
640
641
642
643
644 acquire_console_sem();
645 if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
646 console->next = console_drivers;
647 console_drivers = console;
648 } else {
649 console->next = console_drivers->next;
650 console_drivers->next = console;
651 }
652 if (console->flags & CON_PRINTBUFFER) {
653
654
655
656 spin_lock_irqsave(&logbuf_lock, flags);
657 con_start = log_start;
658 spin_unlock_irqrestore(&logbuf_lock, flags);
659 }
660 release_console_sem();
661}
662EXPORT_SYMBOL(register_console);
663
664int unregister_console(struct console * console)
665{
666 struct console *a,*b;
667 int res = 1;
668
669 acquire_console_sem();
670 if (console_drivers == console) {
671 console_drivers=console->next;
672 res = 0;
673 } else {
674 for (a=console_drivers->next, b=console_drivers ;
675 a; b=a, a=b->next) {
676 if (a == console) {
677 b->next = a->next;
678 res = 0;
679 break;
680 }
681 }
682 }
683
684
685
686
687
688 if (console_drivers == NULL)
689 preferred_console = -1;
690
691
692 release_console_sem();
693 return res;
694}
695EXPORT_SYMBOL(unregister_console);
696
697
698
699
700
701
702
703
704void tty_write_message(struct tty_struct *tty, char *msg)
705{
706 if (tty && tty->driver.write)
707 tty->driver.write(tty, 0, msg, strlen(msg));
708 return;
709}
710