linux-old/kernel/printk.c
<<
>>
Prefs
   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
  24#define LOG_BUF_LEN     4096
  25
  26static char buf[1024];
  27
  28extern void console_print(const char *);
  29
  30#define DEFAULT_MESSAGE_LOGLEVEL 7 /* KERN_DEBUG */
  31#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything more serious than KERN_DEBUG */
  32
  33unsigned long log_size = 0;
  34struct wait_queue * log_wait = NULL;
  35int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  36
  37static void (*console_print_proc)(const char *) = 0;
  38static char log_buf[LOG_BUF_LEN];
  39static unsigned long log_start = 0;
  40static unsigned long logged_chars = 0;
  41
  42/*
  43 * Commands to sys_syslog:
  44 *
  45 *      0 -- Close the log.  Currently a NOP.
  46 *      1 -- Open the log. Currently a NOP.
  47 *      2 -- Read from the log.
  48 *      3 -- Read up to the last 4k of messages in the ring buffer.
  49 *      4 -- Read and clear last 4k of messages in the ring buffer
  50 *      5 -- Clear ring buffer.
  51 *      6 -- Disable printk's to console
  52 *      7 -- Enable printk's to console
  53 *      8 -- Set level of messages printed to console
  54 */
  55asmlinkage int sys_syslog(int type, char * buf, int len)
  56{
  57        unsigned long i, j, count;
  58        int do_clear = 0;
  59        char c;
  60        int error;
  61
  62        if ((type != 3) && !suser())
  63                return -EPERM;
  64        switch (type) {
  65                case 0:         /* Close log */
  66                        return 0;
  67                case 1:         /* Open log */
  68                        return 0;
  69                case 2:         /* Read from log */
  70                        if (!buf || len < 0)
  71                                return -EINVAL;
  72                        if (!len)
  73                                return 0;
  74                        error = verify_area(VERIFY_WRITE,buf,len);
  75                        if (error)
  76                                return error;
  77                        cli();
  78                        while (!log_size) {
  79                                if (current->signal & ~current->blocked) {
  80                                        sti();
  81                                        return -ERESTARTSYS;
  82                                }
  83                                interruptible_sleep_on(&log_wait);
  84                        }
  85                        i = 0;
  86                        while (log_size && i < len) {
  87                                c = *((char *) log_buf+log_start);
  88                                log_start++;
  89                                log_size--;
  90                                log_start &= LOG_BUF_LEN-1;
  91                                sti();
  92                                put_fs_byte(c,buf);
  93                                buf++;
  94                                i++;
  95                                cli();
  96                        }
  97                        sti();
  98                        return i;
  99                case 4:         /* Read/clear last kernel messages */
 100                        do_clear = 1; 
 101                        /* FALL THRU */
 102                case 3:         /* Read last kernel messages */
 103                        if (!buf || len < 0)
 104                                return -EINVAL;
 105                        if (!len)
 106                                return 0;
 107                        error = verify_area(VERIFY_WRITE,buf,len);
 108                        if (error)
 109                                return error;
 110                        count = len;
 111                        if (count > LOG_BUF_LEN)
 112                                count = LOG_BUF_LEN;
 113                        if (count > logged_chars)
 114                                count = logged_chars;
 115                        j = log_start + log_size - count;
 116                        for (i = 0; i < count; i++) {
 117                                c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
 118                                put_fs_byte(c, buf++);
 119                        }
 120                        if (do_clear)
 121                                logged_chars = 0;
 122                        return i;
 123                case 5:         /* Clear ring buffer */
 124                        logged_chars = 0;
 125                        return 0;
 126                case 6:         /* Disable logging to console */
 127                        console_loglevel = 1; /* only panic messages shown */
 128                        return 0;
 129                case 7:         /* Enable logging to console */
 130                        console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
 131                        return 0;
 132                case 8:
 133                        if (len < 1 || len > 8)
 134                                return -EINVAL;
 135                        console_loglevel = len;
 136                        return 0;
 137        }
 138        return -EINVAL;
 139}
 140
 141
 142asmlinkage int printk(const char *fmt, ...)
 143{
 144        va_list args;
 145        int i;
 146        char *msg, *p, *buf_end;
 147        static char msg_level = -1;
 148        long flags;
 149
 150        save_flags(flags);
 151        cli();
 152        va_start(args, fmt);
 153        i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
 154        buf_end = buf + 3 + i;
 155        va_end(args);
 156        for (p = buf + 3; p < buf_end; p++) {
 157                msg = p;
 158                if (msg_level < 0) {
 159                        if (
 160                                p[0] != '<' ||
 161                                p[1] < '0' || 
 162                                p[1] > '7' ||
 163                                p[2] != '>'
 164                        ) {
 165                                p -= 3;
 166                                p[0] = '<';
 167                                p[1] = DEFAULT_MESSAGE_LOGLEVEL - 1 + '0';
 168                                p[2] = '>';
 169                        } else
 170                                msg += 3;
 171                        msg_level = p[1] - '0';
 172                }
 173                for (; p < buf_end; p++) {
 174                        log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
 175                        if (log_size < LOG_BUF_LEN)
 176                                log_size++;
 177                        else {
 178                                log_start++;
 179                                log_start &= LOG_BUF_LEN-1;
 180                        }
 181                        logged_chars++;
 182                        if (*p == '\n')
 183                                break;
 184                }
 185                if (msg_level < console_loglevel && console_print_proc) {
 186                        char tmp = p[1];
 187                        p[1] = '\0';
 188                        (*console_print_proc)(msg);
 189                        p[1] = tmp;
 190                }
 191                if (*p == '\n')
 192                        msg_level = -1;
 193        }
 194        restore_flags(flags);
 195        wake_up_interruptible(&log_wait);
 196        return i;
 197}
 198
 199/*
 200 * The console driver calls this routine during kernel initialization
 201 * to register the console printing procedure with printk() and to
 202 * print any messages that were printed by the kernel before the
 203 * console driver was initialized.
 204 */
 205void register_console(void (*proc)(const char *))
 206{
 207        int     i,j;
 208        int     p = log_start;
 209        char    buf[16];
 210        char    msg_level = -1;
 211        char    *q;
 212
 213        console_print_proc = proc;
 214
 215        for (i=0,j=0; i < log_size; i++) {
 216                buf[j++] = log_buf[p];
 217                p++; p &= LOG_BUF_LEN-1;
 218                if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
 219                        continue;
 220                buf[j] = 0;
 221                q = buf;
 222                if (msg_level < 0) {
 223                        msg_level = buf[1] - '0';
 224                        q = buf + 3;
 225                }
 226                if (msg_level < console_loglevel)
 227                        (*proc)(q);
 228                if (buf[j-1] == '\n')
 229                        msg_level = -1;
 230                j = 0;
 231        }
 232}
 233
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.