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 * Modified for sysctl support, 1/8/97, Chris Horn.
  13 */
  14
  15#include <stdarg.h>
  16
  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#include <linux/smp.h>
  26#include <linux/smp_lock.h>
  27#include <linux/console.h>
  28#include <linux/init.h>
  29
  30#include <asm/uaccess.h>
  31
  32#define LOG_BUF_LEN     8192
  33
  34static char buf[1024];
  35
  36/* printk's without a loglevel use this.. */
  37#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
  38
  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 */
  42
  43unsigned long log_size = 0;
  44struct wait_queue * log_wait = NULL;
  45
  46/* Keep together for sysctl support */
  47int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  48int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
  49int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
  50int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  51
  52struct console *console_drivers = NULL;
  53static char log_buf[LOG_BUF_LEN];
  54static unsigned long log_start = 0;
  55static unsigned long logged_chars = 0;
  56
  57/*
  58 * Commands to sys_syslog:
  59 *
  60 *      0 -- Close the log.  Currently a NOP.
  61 *      1 -- Open the log. Currently a NOP.
  62 *      2 -- Read from the log.
  63 *      3 -- Read up to the last 4k of messages in the ring buffer.
  64 *      4 -- Read and clear last 4k of messages in the ring buffer
  65 *      5 -- Clear ring buffer.
  66 *      6 -- Disable printk's to console
  67 *      7 -- Enable printk's to console
  68 *      8 -- Set level of messages printed to console
  69 */
  70asmlinkage int sys_syslog(int type, char * buf, int len)
  71{
  72        unsigned long i, j, count;
  73        int do_clear = 0;
  74        char c;
  75        int error = -EPERM;
  76
  77        lock_kernel();
  78        if ((type != 3) && !suser())
  79                goto out;
  80        error = 0;
  81        switch (type) {
  82        case 0:         /* Close log */
  83                break;
  84        case 1:         /* Open log */
  85                break;
  86        case 2:         /* Read from log */
  87                error = -EINVAL;
  88                if (!buf || len < 0)
  89                        goto out;
  90                error = 0;
  91                if (!len)
  92                        goto out;
  93                error = verify_area(VERIFY_WRITE,buf,len);
  94                if (error)
  95                        goto out;
  96                cli();
  97                error = -ERESTARTSYS;
  98                while (!log_size) {
  99                        if (signal_pending(current)) {
 100                                sti();
 101                                goto out;
 102                        }
 103                        interruptible_sleep_on(&log_wait);
 104                }
 105                i = 0;
 106                while (log_size && i < len) {
 107                        c = *((char *) log_buf+log_start);
 108                        log_start++;
 109                        log_size--;
 110                        log_start &= LOG_BUF_LEN-1;
 111                        sti();
 112                        put_user(c,buf);
 113                        buf++;
 114                        i++;
 115                        cli();
 116                }
 117                sti();
 118                error = i;
 119                break;
 120        case 4:         /* Read/clear last kernel messages */
 121                do_clear = 1; 
 122                /* FALL THRU */
 123        case 3:         /* Read last kernel messages */
 124                error = -EINVAL;
 125                if (!buf || len < 0)
 126                        goto out;
 127                error = 0;
 128                if (!len)
 129                        goto out;
 130                error = verify_area(VERIFY_WRITE,buf,len);
 131                if (error)
 132                        goto out;
 133                count = len;
 134                if (count > LOG_BUF_LEN)
 135                        count = LOG_BUF_LEN;
 136                if (count > logged_chars)
 137                        count = logged_chars;
 138                j = log_start + log_size - count;
 139                for (i = 0; i < count; i++) {
 140                        c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
 141                        put_user(c, buf++);
 142                }
 143                if (do_clear)
 144                        logged_chars = 0;
 145                error = i;
 146                break;
 147        case 5:         /* Clear ring buffer */
 148                logged_chars = 0;
 149                break;
 150        case 6:         /* Disable logging to console */
 151                console_loglevel = minimum_console_loglevel;
 152                break;
 153        case 7:         /* Enable logging to console */
 154                console_loglevel = default_console_loglevel;
 155                break;
 156        case 8:
 157                error = -EINVAL;
 158                if (len < 1 || len > 8)
 159                        goto out;
 160                if (len < minimum_console_loglevel)
 161                        len = minimum_console_loglevel;
 162                console_loglevel = len;
 163                error = 0;
 164                break;
 165        default:
 166                error = -EINVAL;
 167                break;
 168        }
 169out:
 170        unlock_kernel();
 171        return error;
 172}
 173
 174
 175asmlinkage int printk(const char *fmt, ...)
 176{
 177        va_list args;
 178        int i;
 179        char *msg, *p, *buf_end;
 180        int line_feed;
 181        static signed char msg_level = -1;
 182        long flags;
 183
 184        __save_flags(flags);
 185        __cli();
 186        va_start(args, fmt);
 187        i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
 188        buf_end = buf + 3 + i;
 189        va_end(args);
 190        for (p = buf + 3; p < buf_end; p++) {
 191                msg = p;
 192                if (msg_level < 0) {
 193                        if (
 194                                p[0] != '<' ||
 195                                p[1] < '0' || 
 196                                p[1] > '7' ||
 197                                p[2] != '>'
 198                        ) {
 199                                p -= 3;
 200                                p[0] = '<';
 201                                p[1] = default_message_loglevel + '0';
 202                                p[2] = '>';
 203                        } else
 204                                msg += 3;
 205                        msg_level = p[1] - '0';
 206                }
 207                line_feed = 0;
 208                for (; p < buf_end; p++) {
 209                        log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
 210                        if (log_size < LOG_BUF_LEN)
 211                                log_size++;
 212                        else {
 213                                log_start++;
 214                                log_start &= LOG_BUF_LEN-1;
 215                        }
 216                        logged_chars++;
 217                        if (*p == '\n') {
 218                                line_feed = 1;
 219                                break;
 220                        }
 221                }
 222                if (msg_level < console_loglevel && console_drivers) {
 223                        struct console *c = console_drivers;
 224                        while(c) {
 225                                if (c->write)
 226                                        c->write(msg, p - msg + line_feed);
 227                                c = c->next;
 228                        }
 229                }
 230                if (line_feed)
 231                        msg_level = -1;
 232        }
 233        __restore_flags(flags);
 234        wake_up_interruptible(&log_wait);
 235        return i;
 236}
 237
 238void console_print(const char *s)
 239{
 240        struct console *c = console_drivers;
 241        int len = strlen(s);
 242        while(c) {
 243                if (c->write)
 244                        c->write(s, len);
 245                c = c->next;
 246        }
 247}
 248
 249void unblank_console(void)
 250{
 251        struct console *c = console_drivers;
 252        while(c) {
 253                if (c->unblank)
 254                        c->unblank();
 255                c = c->next;
 256        }
 257}
 258
 259/*
 260 * The console driver calls this routine during kernel initialization
 261 * to register the console printing procedure with printk() and to
 262 * print any messages that were printed by the kernel before the
 263 * console driver was initialized.
 264 */
 265__initfunc(void register_console(struct console * console))
 266{
 267        int     i,j,len;
 268        int     p = log_start;
 269        char    buf[16];
 270        signed char msg_level = -1;
 271        char    *q;
 272
 273        console->next = console_drivers;
 274        console_drivers = console;
 275
 276        for (i=0,j=0; i < log_size; i++) {
 277                buf[j++] = log_buf[p];
 278                p++; p &= LOG_BUF_LEN-1;
 279                if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
 280                        continue;
 281                buf[j] = 0;
 282                q = buf;
 283                len = j;
 284                if (msg_level < 0) {
 285                        msg_level = buf[1] - '0';
 286                        q = buf + 3;
 287                        len -= 3;
 288                }
 289                if (msg_level < console_loglevel)
 290                        console->write(q, len);
 291                if (buf[j-1] == '\n')
 292                        msg_level = -1;
 293                j = 0;
 294        }
 295}
 296
 297/*
 298 * Write a message to a certain tty, not just the console. This is used for
 299 * messages that need to be redirected to a specific tty.
 300 * We don't put it into the syslog queue right now maybe in the future if
 301 * really needed.
 302 */
 303void tty_write_message(struct tty_struct *tty, char *msg)
 304{
 305        if (tty && tty->driver.write)
 306                tty->driver.write(tty, 0, msg, strlen(msg));
 307        return;
 308}
 309
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.