~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/kernel/printk.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/kernel/printk.c
  3  *
  4  *  Copyright (C) 1991, 1992  Linus Torvalds
  5  *
  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.
 13  * Fixed SMP synchronization, 08/08/99, Manfred Spraul 
 14  *     manfreds@colorfullife.com
 15  */
 16 
 17 #include <linux/mm.h>
 18 #include <linux/tty_driver.h>
 19 #include <linux/smp_lock.h>
 20 #include <linux/console.h>
 21 #include <linux/init.h>
 22 
 23 #include <asm/uaccess.h>
 24 
 25 #define LOG_BUF_LEN     (16384)
 26 #define LOG_BUF_MASK    (LOG_BUF_LEN-1)
 27 
 28 static char buf[1024];
 29 
 30 /* printk's without a loglevel use this.. */
 31 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 32 
 33 /* We show everything that is MORE important than this.. */
 34 #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
 35 #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
 36 
 37 unsigned long log_size;
 38 DECLARE_WAIT_QUEUE_HEAD(log_wait);
 39 
 40 /* Keep together for sysctl support */
 41 int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
 42 int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
 43 int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
 44 int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
 45 
 46 spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
 47 
 48 struct console *console_drivers;
 49 static char log_buf[LOG_BUF_LEN];
 50 static unsigned long log_start;
 51 static unsigned long logged_chars;
 52 struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
 53 static int preferred_console = -1;
 54 
 55 /*
 56  *      Setup a list of consoles. Called from init/main.c
 57  */
 58 static int __init console_setup(char *str)
 59 {
 60         struct console_cmdline *c;
 61         char name[sizeof(c->name)];
 62         char *s, *options;
 63         int i, idx;
 64 
 65         /*
 66          *      Decode str into name, index, options.
 67          */
 68         if (str[0] >= '' && str[0] <= '9') {
 69                 strcpy(name, "ttyS");
 70                 strncpy(name + 4, str, sizeof(name) - 5);
 71         } else
 72                 strncpy(name, str, sizeof(name) - 1);
 73         name[sizeof(name) - 1] = 0;
 74         if ((options = strchr(str, ',')) != NULL)
 75                 *(options++) = 0;
 76 #ifdef __sparc__
 77         if (!strcmp(str, "ttya"))
 78                 strcpy(name, "ttyS0");
 79         if (!strcmp(str, "ttyb"))
 80                 strcpy(name, "ttyS1");
 81 #endif
 82         for(s = name; *s; s++)
 83                 if (*s >= '' && *s <= '9')
 84                         break;
 85         idx = simple_strtoul(s, NULL, 10);
 86         *s = 0;
 87 
 88         /*
 89          *      See if this tty is not yet registered, and
 90          *      if we have a slot free.
 91          */
 92         for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
 93                 if (strcmp(console_cmdline[i].name, name) == 0 &&
 94                           console_cmdline[i].index == idx) {
 95                                 preferred_console = i;
 96                                 return 1;
 97                 }
 98         if (i == MAX_CMDLINECONSOLES)
 99                 return 1;
100         preferred_console = i;
101         c = &console_cmdline[i];
102         memcpy(c->name, name, sizeof(c->name));
103         c->options = options;
104         c->index = idx;
105         return 1;
106 }
107 
108 __setup("console=", console_setup);
109 
110 /*
111  * Commands to do_syslog:
112  *
113  *      0 -- Close the log.  Currently a NOP.
114  *      1 -- Open the log. Currently a NOP.
115  *      2 -- Read from the log.
116  *      3 -- Read all messages remaining in the ring buffer.
117  *      4 -- Read and clear all messages remaining in the ring buffer
118  *      5 -- Clear ring buffer.
119  *      6 -- Disable printk's to console
120  *      7 -- Enable printk's to console
121  *      8 -- Set level of messages printed to console
122  */
123 int do_syslog(int type, char * buf, int len)
124 {
125         unsigned long i, j, limit, count;
126         int do_clear = 0;
127         char c;
128         int error = -EPERM;
129 
130         error = 0;
131         switch (type) {
132         case 0:         /* Close log */
133                 break;
134         case 1:         /* Open log */
135                 break;
136         case 2:         /* Read from log */
137                 error = -EINVAL;
138                 if (!buf || len < 0)
139                         goto out;
140                 error = 0;
141                 if (!len)
142                         goto out;
143                 error = verify_area(VERIFY_WRITE,buf,len);
144                 if (error)
145                         goto out;
146                 error = wait_event_interruptible(log_wait, log_size);
147                 if (error)
148                         goto out;
149                 i = 0;
150                 spin_lock_irq(&console_lock);
151                 while (log_size && i < len) {
152                         c = log_buf[log_start & LOG_BUF_MASK];
153                         log_start++;
154                         log_size--;
155                         spin_unlock_irq(&console_lock);
156                         __put_user(c,buf);
157                         buf++;
158                         i++;
159                         spin_lock_irq(&console_lock);
160                 }
161                 spin_unlock_irq(&console_lock);
162                 error = i;
163                 break;
164         case 4:         /* Read/clear last kernel messages */
165                 do_clear = 1; 
166                 /* FALL THRU */
167         case 3:         /* Read last kernel messages */
168                 error = -EINVAL;
169                 if (!buf || len < 0)
170                         goto out;
171                 error = 0;
172                 if (!len)
173                         goto out;
174                 error = verify_area(VERIFY_WRITE,buf,len);
175                 if (error)
176                         goto out;
177                 count = len;
178                 if (count > LOG_BUF_LEN)
179                         count = LOG_BUF_LEN;
180                 spin_lock_irq(&console_lock);
181                 if (count > logged_chars)
182                         count = logged_chars;
183                 if (do_clear)
184                         logged_chars = 0;
185                 limit = log_start + log_size;
186                 /*
187                  * __put_user() could sleep, and while we sleep
188                  * printk() could overwrite the messages 
189                  * we try to copy to user space. Therefore
190                  * the messages are copied in reverse. <manfreds>
191                  */
192                 for(i=0;i < count;i++) {
193                         j = limit-1-i;
194                         if (j+LOG_BUF_LEN < log_start+log_size)
195                                 break;
196                         c = log_buf[ j  & LOG_BUF_MASK ];
197                         spin_unlock_irq(&console_lock);
198                         __put_user(c,&buf[count-1-i]);
199                         spin_lock_irq(&console_lock);
200                 }
201                 spin_unlock_irq(&console_lock);
202                 error = i;
203                 if(i != count) {
204                         int offset = count-error;
205                         /* buffer overflow during copy, correct user buffer. */
206                         for(i=0;i<error;i++) {
207                                 __get_user(c,&buf[i+offset]);
208                                 __put_user(c,&buf[i]);
209                         }
210                 }
211 
212                 break;
213         case 5:         /* Clear ring buffer */
214                 spin_lock_irq(&console_lock);
215                 logged_chars = 0;
216                 spin_unlock_irq(&console_lock);
217                 break;
218         case 6:         /* Disable logging to console */
219                 spin_lock_irq(&console_lock);
220                 console_loglevel = minimum_console_loglevel;
221                 spin_unlock_irq(&console_lock);
222                 break;
223         case 7:         /* Enable logging to console */
224                 spin_lock_irq(&console_lock);
225                 console_loglevel = default_console_loglevel;
226                 spin_unlock_irq(&console_lock);
227                 break;
228         case 8:
229                 error = -EINVAL;
230                 if (len < 1 || len > 8)
231                         goto out;
232                 if (len < minimum_console_loglevel)
233                         len = minimum_console_loglevel;
234                 spin_lock_irq(&console_lock);
235                 console_loglevel = len;
236                 spin_unlock_irq(&console_lock);
237                 error = 0;
238                 break;
239         default:
240                 error = -EINVAL;
241                 break;
242         }
243 out:
244         return error;
245 }
246 
247 asmlinkage long sys_syslog(int type, char * buf, int len)
248 {
249         if ((type != 3) && !capable(CAP_SYS_ADMIN))
250                 return -EPERM;
251         return do_syslog(type, buf, len);
252 }
253 
254 asmlinkage int printk(const char *fmt, ...)
255 {
256         va_list args;
257         int i;
258         char *msg, *p, *buf_end;
259         int line_feed;
260         static signed char msg_level = -1;
261         long flags;
262 
263         spin_lock_irqsave(&console_lock, flags);
264         va_start(args, fmt);
265         i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
266         buf_end = buf + 3 + i;
267         va_end(args);
268         for (p = buf + 3; p < buf_end; p++) {
269                 msg = p;
270                 if (msg_level < 0) {
271                         if (
272                                 p[0] != '<' ||
273                                 p[1] < '' || 
274                                 p[1] > '7' ||
275                                 p[2] != '>'
276                         ) {
277                                 p -= 3;
278                                 p[0] = '<';
279                                 p[1] = default_message_loglevel + '';
280                                 p[2] = '>';
281                         } else
282                                 msg += 3;
283                         msg_level = p[1] - '';
284                 }
285                 line_feed = 0;
286                 for (; p < buf_end; p++) {
287                         log_buf[(log_start+log_size) & LOG_BUF_MASK] = *p;
288                         if (log_size < LOG_BUF_LEN)
289                                 log_size++;
290                         else
291                                 log_start++;
292 
293                         logged_chars++;
294                         if (*p == '\n') {
295                                 line_feed = 1;
296                                 break;
297                         }
298                 }
299                 if (msg_level < console_loglevel && console_drivers) {
300                         struct console *c = console_drivers;
301                         while(c) {
302                                 if ((c->flags & CON_ENABLED) && c->write)
303                                         c->write(c, msg, p - msg + line_feed);
304                                 c = c->next;
305                         }
306                 }
307                 if (line_feed)
308                         msg_level = -1;
309         }
310         spin_unlock_irqrestore(&console_lock, flags);
311         wake_up_interruptible(&log_wait);
312         return i;
313 }
314 
315 void console_print(const char *s)
316 {
317         struct console *c;
318         unsigned long flags;
319         int len = strlen(s);
320 
321         spin_lock_irqsave(&console_lock, flags);
322         c = console_drivers;
323         while(c) {
324                 if ((c->flags & CON_ENABLED) && c->write)
325                         c->write(c, s, len);
326                 c = c->next;
327         }
328         spin_unlock_irqrestore(&console_lock, flags);
329 }
330 
331 void unblank_console(void)
332 {
333         struct console *c;
334         unsigned long flags;
335         
336         spin_lock_irqsave(&console_lock, flags);
337         c = console_drivers;
338         while(c) {
339                 if ((c->flags & CON_ENABLED) && c->unblank)
340                         c->unblank();
341                 c = c->next;
342         }
343         spin_unlock_irqrestore(&console_lock, flags);
344 }
345 
346 /*
347  * The console driver calls this routine during kernel initialization
348  * to register the console printing procedure with printk() and to
349  * print any messages that were printed by the kernel before the
350  * console driver was initialized.
351  */
352 void register_console(struct console * console)
353 {
354         int     i, j,len;
355         int     p;
356         char    buf[16];
357         signed char msg_level = -1;
358         char    *q;
359         unsigned long flags;
360 
361         /*
362          *      See if we want to use this console driver. If we
363          *      didn't select a console we take the first one
364          *      that registers here.
365          */
366         if (preferred_console < 0) {
367                 if (console->index < 0)
368                         console->index = 0;
369                 if (console->setup == NULL ||
370                     console->setup(console, NULL) == 0) {
371                         console->flags |= CON_ENABLED | CON_CONSDEV;
372                         preferred_console = 0;
373                 }
374         }
375 
376         /*
377          *      See if this console matches one we selected on
378          *      the command line.
379          */
380         for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
381                 if (strcmp(console_cmdline[i].name, console->name) != 0)
382                         continue;
383                 if (console->index >= 0 &&
384                     console->index != console_cmdline[i].index)
385                         continue;
386                 if (console->index < 0)
387                         console->index = console_cmdline[i].index;
388                 if (console->setup &&
389                     console->setup(console, console_cmdline[i].options) != 0)
390                         break;
391                 console->flags |= CON_ENABLED;
392                 console->index = console_cmdline[i].index;
393                 if (i == preferred_console)
394                         console->flags |= CON_CONSDEV;
395                 break;
396         }
397 
398         if (!(console->flags & CON_ENABLED))
399                 return;
400 
401         /*
402          *      Put this console in the list - keep the
403          *      preferred driver at the head of the list.
404          */
405         spin_lock_irqsave(&console_lock, flags);
406         if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
407                 console->next = console_drivers;
408                 console_drivers = console;
409         } else {
410                 console->next = console_drivers->next;
411                 console_drivers->next = console;
412         }
413         if ((console->flags & CON_PRINTBUFFER) == 0)
414                 goto done;
415         /*
416          *      Print out buffered log messages.
417          */
418         p = log_start & LOG_BUF_MASK;
419 
420         for (i=0,j=0; i < log_size; i++) {
421                 buf[j++] = log_buf[p];
422                 p = (p+1) & LOG_BUF_MASK;
423                 if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
424                         continue;
425                 buf[j] = 0;
426                 q = buf;
427                 len = j;
428                 if (msg_level < 0) {
429                         if(buf[0] == '<' &&
430                                 buf[1] >= '' &&
431                                 buf[1] <= '7' &&
432                                 buf[2] == '>') {
433                                 msg_level = buf[1] - '';
434                                 q = buf + 3;
435                                 len -= 3;
436                         } else
437                         {
438                                 msg_level = default_message_loglevel; 
439                         }
440                 }
441                 if (msg_level < console_loglevel)
442                         console->write(console, q, len);
443                 if (buf[j-1] == '\n')
444                         msg_level = -1;
445                 j = 0;
446         }
447 done:
448         spin_unlock_irqrestore(&console_lock, flags);
449 }
450 
451 
452 int unregister_console(struct console * console)
453 {
454         struct console *a,*b;
455         unsigned long flags;
456         int res = 1;
457 
458         spin_lock_irqsave(&console_lock, flags);
459         if (console_drivers == console) {
460                 console_drivers=console->next;
461                 res = 0;
462         } else
463         {
464                 for (a=console_drivers->next, b=console_drivers ;
465                      a; b=a, a=b->next) {
466                         if (a == console) {
467                                 b->next = a->next;
468                                 res = 0;
469                                 break;
470                         }  
471                 }
472         }
473         
474         /* If last console is removed, we re-enable picking the first
475          * one that gets registered. Without that, pmac early boot console
476          * would prevent fbcon from taking over.
477          */
478         if (console_drivers == NULL)
479                 preferred_console = -1;
480                 
481 
482         spin_unlock_irqrestore(&console_lock, flags);
483         return res;
484 }
485         
486 /*
487  * Write a message to a certain tty, not just the console. This is used for
488  * messages that need to be redirected to a specific tty.
489  * We don't put it into the syslog queue right now maybe in the future if
490  * really needed.
491  */
492 void tty_write_message(struct tty_struct *tty, char *msg)
493 {
494         if (tty && tty->driver.write)
495                 tty->driver.write(tty, 0, msg, strlen(msg));
496         return;
497 }
498 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.