root/kernel/printk.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_syslog
  2. printk
  3. register_console
  4. tty_write_message

   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  */
  13 
  14 #include <stdarg.h>
  15 
  16 #include <asm/segment.h>
  17 #include <asm/system.h>
  18 
  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 
  26 #define LOG_BUF_LEN     4096
  27 
  28 static char buf[1024];
  29 
  30 extern void console_print(const char *);
  31 
  32 /* printk's without a loglevel use this.. */
  33 #define DEFAULT_MESSAGE_LOGLEVEL 5 /* KERN_NOTICE */
  34 
  35 /* We show everything that is more important than this.. */
  36 #define MINIMUM_CONSOLE_LOGLEVEL 6 /* Minimum loglevel we let people use */
  37 #define DEFAULT_CONSOLE_LOGLEVEL 6 /* anything more serious than KERN_INFO */
  38 
  39 unsigned long log_size = 0;
  40 struct wait_queue * log_wait = NULL;
  41 int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  42 
  43 static void (*console_print_proc)(const char *) = 0;
  44 static char log_buf[LOG_BUF_LEN];
  45 static unsigned long log_start = 0;
  46 static unsigned long logged_chars = 0;
  47 
  48 /*
  49  * Commands to sys_syslog:
  50  *
  51  *      0 -- Close the log.  Currently a NOP.
  52  *      1 -- Open the log. Currently a NOP.
  53  *      2 -- Read from the log.
  54  *      3 -- Read up to the last 4k of messages in the ring buffer.
  55  *      4 -- Read and clear last 4k of messages in the ring buffer
  56  *      5 -- Clear ring buffer.
  57  *      6 -- Disable printk's to console
  58  *      7 -- Enable printk's to console
  59  *      8 -- Set level of messages printed to console
  60  */
  61 asmlinkage int sys_syslog(int type, char * buf, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63         unsigned long i, j, count;
  64         int do_clear = 0;
  65         char c;
  66         int error;
  67 
  68         if ((type != 3) && !suser())
  69                 return -EPERM;
  70         switch (type) {
  71                 case 0:         /* Close log */
  72                         return 0;
  73                 case 1:         /* Open log */
  74                         return 0;
  75                 case 2:         /* Read from log */
  76                         if (!buf || len < 0)
  77                                 return -EINVAL;
  78                         if (!len)
  79                                 return 0;
  80                         error = verify_area(VERIFY_WRITE,buf,len);
  81                         if (error)
  82                                 return error;
  83                         cli();
  84                         while (!log_size) {
  85                                 if (current->signal & ~current->blocked) {
  86                                         sti();
  87                                         return -ERESTARTSYS;
  88                                 }
  89                                 interruptible_sleep_on(&log_wait);
  90                         }
  91                         i = 0;
  92                         while (log_size && i < len) {
  93                                 c = *((char *) log_buf+log_start);
  94                                 log_start++;
  95                                 log_size--;
  96                                 log_start &= LOG_BUF_LEN-1;
  97                                 sti();
  98                                 put_user(c,buf);
  99                                 buf++;
 100                                 i++;
 101                                 cli();
 102                         }
 103                         sti();
 104                         return i;
 105                 case 4:         /* Read/clear last kernel messages */
 106                         do_clear = 1; 
 107                         /* FALL THRU */
 108                 case 3:         /* Read last kernel messages */
 109                         if (!buf || len < 0)
 110                                 return -EINVAL;
 111                         if (!len)
 112                                 return 0;
 113                         error = verify_area(VERIFY_WRITE,buf,len);
 114                         if (error)
 115                                 return error;
 116                         count = len;
 117                         if (count > LOG_BUF_LEN)
 118                                 count = LOG_BUF_LEN;
 119                         if (count > logged_chars)
 120                                 count = logged_chars;
 121                         j = log_start + log_size - count;
 122                         for (i = 0; i < count; i++) {
 123                                 c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
 124                                 put_user(c, buf++);
 125                         }
 126                         if (do_clear)
 127                                 logged_chars = 0;
 128                         return i;
 129                 case 5:         /* Clear ring buffer */
 130                         logged_chars = 0;
 131                         return 0;
 132                 case 6:         /* Disable logging to console */
 133                         console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
 134                         return 0;
 135                 case 7:         /* Enable logging to console */
 136                         console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
 137                         return 0;
 138                 case 8:
 139                         if (len < 1 || len > 8)
 140                                 return -EINVAL;
 141                         if (len < MINIMUM_CONSOLE_LOGLEVEL)
 142                                 len = MINIMUM_CONSOLE_LOGLEVEL;
 143                         console_loglevel = len;
 144                         return 0;
 145         }
 146         return -EINVAL;
 147 }
 148 
 149 
 150 asmlinkage int printk(const char *fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152         va_list args;
 153         int i;
 154         char *msg, *p, *buf_end;
 155         static char msg_level = -1;
 156         long flags;
 157 
 158         save_flags(flags);
 159         cli();
 160         va_start(args, fmt);
 161         i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
 162         buf_end = buf + 3 + i;
 163         va_end(args);
 164         for (p = buf + 3; p < buf_end; p++) {
 165                 msg = p;
 166                 if (msg_level < 0) {
 167                         if (
 168                                 p[0] != '<' ||
 169                                 p[1] < '0' || 
 170                                 p[1] > '7' ||
 171                                 p[2] != '>'
 172                         ) {
 173                                 p -= 3;
 174                                 p[0] = '<';
 175                                 p[1] = DEFAULT_MESSAGE_LOGLEVEL + '0';
 176                                 p[2] = '>';
 177                         } else
 178                                 msg += 3;
 179                         msg_level = p[1] - '0';
 180                 }
 181                 for (; p < buf_end; p++) {
 182                         log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
 183                         if (log_size < LOG_BUF_LEN)
 184                                 log_size++;
 185                         else {
 186                                 log_start++;
 187                                 log_start &= LOG_BUF_LEN-1;
 188                         }
 189                         logged_chars++;
 190                         if (*p == '\n')
 191                                 break;
 192                 }
 193                 if (msg_level < console_loglevel && console_print_proc) {
 194                         char tmp = p[1];
 195                         p[1] = '\0';
 196                         (*console_print_proc)(msg);
 197                         p[1] = tmp;
 198                 }
 199                 if (*p == '\n')
 200                         msg_level = -1;
 201         }
 202         restore_flags(flags);
 203         wake_up_interruptible(&log_wait);
 204         return i;
 205 }
 206 
 207 /*
 208  * The console driver calls this routine during kernel initialization
 209  * to register the console printing procedure with printk() and to
 210  * print any messages that were printed by the kernel before the
 211  * console driver was initialized.
 212  */
 213 void register_console(void (*proc)(const char *))
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215         int     i,j;
 216         int     p = log_start;
 217         char    buf[16];
 218         char    msg_level = -1;
 219         char    *q;
 220 
 221         console_print_proc = proc;
 222 
 223         for (i=0,j=0; i < log_size; i++) {
 224                 buf[j++] = log_buf[p];
 225                 p++; p &= LOG_BUF_LEN-1;
 226                 if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
 227                         continue;
 228                 buf[j] = 0;
 229                 q = buf;
 230                 if (msg_level < 0) {
 231                         msg_level = buf[1] - '0';
 232                         q = buf + 3;
 233                 }
 234                 if (msg_level < console_loglevel)
 235                         (*proc)(q);
 236                 if (buf[j-1] == '\n')
 237                         msg_level = -1;
 238                 j = 0;
 239         }
 240 }
 241 
 242 /*
 243  * Write a message to a certain tty, not just the console. This is used for
 244  * messages that need to be redirected to a specific tty.
 245  * We don't put it into the syslog queue right now maybe in the future if
 246  * really needed.
 247  */
 248 void tty_write_message(struct tty_struct *tty, char *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 249 {
 250         if (tty && tty->driver.write)
 251                 tty->driver.write(tty, 0, msg, strlen(msg));
 252         return;
 253 }

/* [previous][next][first][last][top][bottom][index][help] */