Import 2.1.81
[davej-history.git] / kernel / printk.c
blobde7daeb3af6ee755ff226a3298d56b595b70dcc8
1 /*
2 * linux/kernel/printk.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
6 * Modified to make sys_syslog() more flexible: added commands to
7 * return the last 4k of kernel messages, regardless of whether
8 * they've been read or not. Added option to suppress kernel printk's
9 * to the console. Added hook for sending the console messages
10 * elsewhere, in preparation for a serial line console (someday).
11 * Ted Ts'o, 2/11/93.
12 * Modified for sysctl support, 1/8/97, Chris Horn.
15 #include <stdarg.h>
17 #include <asm/system.h>
19 #include <linux/errno.h>
20 #include <linux/sched.h>
21 #include <linux/kernel.h>
22 #include <linux/mm.h>
23 #include <linux/tty.h>
24 #include <linux/tty_driver.h>
25 #include <linux/smp.h>
26 #include <linux/smp_lock.h>
27 #include <linux/console.h>
28 #include <linux/init.h>
30 #include <asm/uaccess.h>
32 #define LOG_BUF_LEN 8192
34 static char buf[1024];
36 /* printk's without a loglevel use this.. */
37 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
39 /* We show everything that is MORE important than this.. */
40 #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
41 #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
43 unsigned long log_size = 0;
44 struct wait_queue * log_wait = NULL;
46 /* Keep together for sysctl support */
47 int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
48 int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
49 int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
50 int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
52 struct console *console_drivers = NULL;
53 static char log_buf[LOG_BUF_LEN];
54 static unsigned long log_start = 0;
55 static unsigned long logged_chars = 0;
56 struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
57 static int selected_console = 0;
60 * Setup a list of consoles. Called from init/main.c
62 __initfunc(void console_setup(char *str, int *ints))
64 char *s;
65 int i;
66 struct console_cmdline *c;
68 for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
70 if (i == MAX_CMDLINECONSOLES)
71 return;
72 c = &console_cmdline[i];
73 selected_console = 1;
75 if (str[0] >= '0' && str[0] <= '9') {
76 strcpy(c->name, "ttyS");
77 strncpy(c->name + 4, str, sizeof(c->name) - 5);
78 } else
79 strncpy(c->name, str, sizeof(c->name) - 1);
80 if ((c->options = strchr(str, ',')) != NULL)
81 *(c->options++) = 0;
82 #ifdef __sparc__
83 if (!strcmp(str, "ttya"))
84 strcpy(c->name, "ttyS0");
85 if (!strcmp(str, "ttyb"))
86 strcpy(c->name, "ttyS1");
87 #endif
89 for(s = c->name; *s; s++)
90 if (*s >= '0' && *s <= '9')
91 break;
92 c->index = simple_strtoul(s, NULL, 10);
93 *s = 0;
98 * Commands to sys_syslog:
100 * 0 -- Close the log. Currently a NOP.
101 * 1 -- Open the log. Currently a NOP.
102 * 2 -- Read from the log.
103 * 3 -- Read up to the last 4k of messages in the ring buffer.
104 * 4 -- Read and clear last 4k of messages in the ring buffer
105 * 5 -- Clear ring buffer.
106 * 6 -- Disable printk's to console
107 * 7 -- Enable printk's to console
108 * 8 -- Set level of messages printed to console
110 asmlinkage int sys_syslog(int type, char * buf, int len)
112 unsigned long i, j, count, flags;
113 int do_clear = 0;
114 char c;
115 int error = -EPERM;
117 lock_kernel();
118 if ((type != 3) && !suser())
119 goto out;
120 error = 0;
121 switch (type) {
122 case 0: /* Close log */
123 break;
124 case 1: /* Open log */
125 break;
126 case 2: /* Read from log */
127 error = -EINVAL;
128 if (!buf || len < 0)
129 goto out;
130 error = 0;
131 if (!len)
132 goto out;
133 error = verify_area(VERIFY_WRITE,buf,len);
134 if (error)
135 goto out;
136 cli();
137 error = -ERESTARTSYS;
138 while (!log_size) {
139 if (signal_pending(current)) {
140 sti();
141 goto out;
143 interruptible_sleep_on(&log_wait);
145 i = 0;
146 while (log_size && i < len) {
147 c = *((char *) log_buf+log_start);
148 log_start++;
149 log_size--;
150 log_start &= LOG_BUF_LEN-1;
151 sti();
152 __put_user(c,buf);
153 buf++;
154 i++;
155 cli();
157 sti();
158 error = i;
159 break;
160 case 4: /* Read/clear last kernel messages */
161 do_clear = 1;
162 /* FALL THRU */
163 case 3: /* Read last kernel messages */
164 error = -EINVAL;
165 if (!buf || len < 0)
166 goto out;
167 error = 0;
168 if (!len)
169 goto out;
170 error = verify_area(VERIFY_WRITE,buf,len);
171 if (error)
172 goto out;
174 * The logged_chars, log_start, and log_size values may
175 * change from an interrupt, so we disable interrupts.
177 __save_flags(flags);
178 __cli();
179 count = len;
180 if (count > LOG_BUF_LEN)
181 count = LOG_BUF_LEN;
182 if (count > logged_chars)
183 count = logged_chars;
184 j = log_start + log_size - count;
185 __restore_flags(flags);
186 for (i = 0; i < count; i++) {
187 c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
188 __put_user(c, buf++);
190 if (do_clear)
191 logged_chars = 0;
192 error = i;
193 break;
194 case 5: /* Clear ring buffer */
195 logged_chars = 0;
196 break;
197 case 6: /* Disable logging to console */
198 console_loglevel = minimum_console_loglevel;
199 break;
200 case 7: /* Enable logging to console */
201 console_loglevel = default_console_loglevel;
202 break;
203 case 8:
204 error = -EINVAL;
205 if (len < 1 || len > 8)
206 goto out;
207 if (len < minimum_console_loglevel)
208 len = minimum_console_loglevel;
209 console_loglevel = len;
210 error = 0;
211 break;
212 default:
213 error = -EINVAL;
214 break;
216 out:
217 unlock_kernel();
218 return error;
221 spinlock_t console_lock;
223 asmlinkage int printk(const char *fmt, ...)
225 va_list args;
226 int i;
227 char *msg, *p, *buf_end;
228 int line_feed;
229 static signed char msg_level = -1;
230 long flags;
232 spin_lock_irqsave(&console_lock, flags);
233 va_start(args, fmt);
234 i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
235 buf_end = buf + 3 + i;
236 va_end(args);
237 for (p = buf + 3; p < buf_end; p++) {
238 msg = p;
239 if (msg_level < 0) {
240 if (
241 p[0] != '<' ||
242 p[1] < '0' ||
243 p[1] > '7' ||
244 p[2] != '>'
246 p -= 3;
247 p[0] = '<';
248 p[1] = default_message_loglevel + '0';
249 p[2] = '>';
250 } else
251 msg += 3;
252 msg_level = p[1] - '0';
254 line_feed = 0;
255 for (; p < buf_end; p++) {
256 log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
257 if (log_size < LOG_BUF_LEN)
258 log_size++;
259 else {
260 log_start++;
261 log_start &= LOG_BUF_LEN-1;
263 logged_chars++;
264 if (*p == '\n') {
265 line_feed = 1;
266 break;
269 if (msg_level < console_loglevel && console_drivers) {
270 struct console *c = console_drivers;
271 while(c) {
272 if ((c->flags & CON_ENABLED) && c->write)
273 c->write(c, msg, p - msg + line_feed);
274 c = c->next;
277 if (line_feed)
278 msg_level = -1;
280 spin_unlock_irqrestore(&console_lock, flags);
281 wake_up_interruptible(&log_wait);
282 return i;
285 void console_print(const char *s)
287 struct console *c = console_drivers;
288 int len = strlen(s);
290 while(c) {
291 if ((c->flags & CON_ENABLED) && c->write)
292 c->write(c, s, len);
293 c = c->next;
297 void unblank_console(void)
299 struct console *c = console_drivers;
300 while(c) {
301 if ((c->flags & CON_ENABLED) && c->unblank)
302 c->unblank();
303 c = c->next;
308 * The console driver calls this routine during kernel initialization
309 * to register the console printing procedure with printk() and to
310 * print any messages that were printed by the kernel before the
311 * console driver was initialized.
313 void register_console(struct console * console)
315 int i,j,len;
316 int p = log_start;
317 char buf[16];
318 signed char msg_level = -1;
319 char *q;
322 * See if we want to use this console driver. If we
323 * didn't select a console we take the first one
324 * that registers here.
326 if (selected_console == 0) {
327 if (console->index < 0)
328 console->index = 0;
329 if (console->setup == NULL ||
330 console->setup(console, NULL) == 0) {
331 console->flags |= CON_ENABLED | CON_FIRST;
332 selected_console = 1;
337 * See if this console matches one we selected on
338 * the command line.
340 for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
341 if (strcmp(console_cmdline[i].name, console->name) != 0)
342 continue;
343 if (console->index >= 0 &&
344 console->index != console_cmdline[i].index)
345 continue;
346 if (console->index < 0) console->index = 0;
347 if (console->setup &&
348 console->setup(console, console_cmdline[i].options) != 0)
349 break;
350 console->flags |= CON_ENABLED;
351 console->index = console_cmdline[i].index;
352 if (i == 0)
353 console->flags |= CON_FIRST;
354 break;
357 if (!(console->flags & CON_ENABLED))
358 return;
361 * Put this console in the list - keep the
362 * preferred driver at the head of the list.
364 if ((console->flags & CON_FIRST) || console_drivers == NULL) {
365 console->next = console_drivers;
366 console_drivers = console;
367 } else {
368 console->next = console_drivers->next;
369 console_drivers->next = console;
371 if ((console->flags & CON_PRINTBUFFER) == 0) return;
374 * Print out buffered log messages.
376 for (i=0,j=0; i < log_size; i++) {
377 buf[j++] = log_buf[p];
378 p++; p &= LOG_BUF_LEN-1;
379 if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
380 continue;
381 buf[j] = 0;
382 q = buf;
383 len = j;
384 if (msg_level < 0) {
385 msg_level = buf[1] - '0';
386 q = buf + 3;
387 len -= 3;
389 if (msg_level < console_loglevel)
390 console->write(console, q, len);
391 if (buf[j-1] == '\n')
392 msg_level = -1;
393 j = 0;
398 int unregister_console(struct console * console)
400 struct console *a,*b;
402 if (console_drivers == console) {
403 console_drivers=console->next;
404 return (0);
406 for (a=console_drivers->next, b=console_drivers ;
407 a; b=a, a=b->next) {
408 if (a == console) {
409 b->next = a->next;
410 return 0;
414 return (1);
418 * Write a message to a certain tty, not just the console. This is used for
419 * messages that need to be redirected to a specific tty.
420 * We don't put it into the syslog queue right now maybe in the future if
421 * really needed.
423 void tty_write_message(struct tty_struct *tty, char *msg)
425 if (tty && tty->driver.write)
426 tty->driver.write(tty, 0, msg, strlen(msg));
427 return;