| /* |
| * linux/kernel/printk.c |
| * |
| * Copyright (C) 1991, 1992 Linus Torvalds |
| * |
| * Modified to make sys_syslog() more flexible: added commands to |
| * return the last 4k of kernel messages, regardless of whether |
| * they've been read or not. Added option to suppress kernel printk's |
| * to the console. Added hook for sending the console messages |
| * elsewhere, in preparation for a serial line console (someday). |
| * Ted Ts'o, 2/11/93. |
| */ |
| |
| #include <stdarg.h> |
| |
| #include <asm/segment.h> |
| #include <asm/system.h> |
| |
| #include <linux/errno.h> |
| #include <linux/sched.h> |
| #include <linux/kernel.h> |
| |
| static char buf[1024]; |
| |
| extern int vsprintf(char * buf, const char * fmt, va_list args); |
| extern void console_print(const char *); |
| |
| static void (*console_print_proc)(const char *) = 0; |
| static char log_buf[4096]; |
| static unsigned long log_start = 0; |
| static unsigned long logged_chars = 0; |
| unsigned long log_size = 0; |
| int log_to_console = 1; |
| struct wait_queue * log_wait = NULL; |
| |
| /* |
| * Commands to sys_syslog: |
| * |
| * 0 -- Close the log. Currently a NOP. |
| * 1 -- Open the log. Currently a NOP. |
| * 2 -- Read from the log. |
| * 3 -- Read up to the last 4k of messages in the ring buffer. |
| * 4 -- Read and clear last 4k of messages in the ring buffer |
| * 5 -- Clear ring buffer. |
| * 6 -- Disable printk's to console |
| * 7 -- Enable printk's to console |
| */ |
| extern "C" int sys_syslog(int type, char * buf, int len) |
| { |
| unsigned long i, j, count; |
| int do_clear = 0; |
| char c; |
| |
| if ((type != 3) && !suser()) |
| return -EPERM; |
| switch (type) { |
| case 0: /* Close log */ |
| return 0; |
| case 1: /* Open log */ |
| return 0; |
| case 2: /* Read from log */ |
| if (!buf || len < 0) |
| return -EINVAL; |
| if (!len) |
| return 0; |
| verify_area(VERIFY_WRITE,buf,len); |
| while (!log_size) { |
| if (current->signal & ~current->blocked) |
| return -ERESTARTSYS; |
| cli(); |
| if (!log_size) |
| interruptible_sleep_on(&log_wait); |
| sti(); |
| } |
| i = 0; |
| while (log_size && i < len) { |
| c = *((char *) log_buf+log_start); |
| log_start++; |
| log_size--; |
| log_start &= 4095; |
| put_fs_byte(c,buf); |
| buf++; |
| i++; |
| } |
| return i; |
| case 4: /* Read/clear last 4k of kernel messages */ |
| do_clear = 1; |
| case 3: /* Read last 4k of kernel messages */ |
| if (!buf || len < 0) |
| return -EINVAL; |
| if (!len) |
| return 0; |
| verify_area(VERIFY_WRITE,buf,len); |
| count = len; |
| if (count > 4096) |
| count = 4096; |
| if (count > logged_chars) |
| count = logged_chars; |
| j = log_start + log_size - count; |
| for (i = 0; i < count; i++) { |
| c = *((char *) log_buf + (j++ & 4095)); |
| put_fs_byte(c, buf++); |
| } |
| if (do_clear) |
| logged_chars = 0; |
| return i; |
| case 5: /* Clear ring buffer */ |
| logged_chars = 0; |
| return 0; |
| case 6: /* Disable logging to console */ |
| log_to_console = 0; |
| return 0; |
| case 7: /* Enable logging to console */ |
| log_to_console = 1; |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| |
| extern "C" int printk(const char *fmt, ...) |
| { |
| va_list args; |
| int i,j; |
| |
| va_start(args, fmt); |
| i=vsprintf(buf,fmt,args); |
| va_end(args); |
| for (j = 0; j < i ; j++) { |
| log_buf[(log_start+log_size) & 4095] = buf[j]; |
| if (log_size < 4096) |
| log_size++; |
| else |
| log_start++; |
| logged_chars++; |
| } |
| wake_up_interruptible(&log_wait); |
| if (log_to_console && console_print_proc) |
| (*console_print_proc)(buf); |
| return i; |
| } |
| |
| /* |
| * The console driver calls this routine during kernel initialization |
| * to register the console printing procedure with printk() and to |
| * print any messages that were printed by the kernel before the |
| * console priver was initialized. |
| */ |
| void register_console(void (*proc)(const char *)) |
| { |
| int i,j; |
| int p = log_start; |
| char buf[16]; |
| |
| console_print_proc = proc; |
| |
| for (i=0,j=0; i < log_size; i++) { |
| buf[j++] = log_buf[p]; |
| p++; p &= 4095; |
| if (j < sizeof(buf)-1) |
| continue; |
| buf[j] = 0; |
| (*proc)(buf); |
| j = 0; |
| } |
| buf[j] = 0; |
| (*proc)(buf); |
| } |