diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 85 |
1 files changed, 79 insertions, 6 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index ebce88c..c461698 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -4,28 +4,101 @@ * (C) 1991 Linus Torvalds */ -/* - * When in kernel-mode, we cannot use printf, as fs is liable to - * point to 'interesting' things. Make a printf with fs-saving, and - * all is well. - */ #include <stdarg.h> #include <stddef.h> +#include <errno.h> +#include <asm/segment.h> +#include <asm/system.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 unsigned long log_page = 0; +static unsigned long log_start = 0; +static unsigned long log_size = 0; +static struct task_struct * log_wait = NULL; + +int sys_syslog(int type, char * buf, int len) +{ + unsigned long i; + char c; + + if (!suser()) + return -EPERM; + switch (type) { + case 0: + i = log_page; + log_page = 0; + free_page(i); + wake_up(&log_wait); + return 0; + case 1: + i = get_free_page(); + if (log_page) { + free_page(i); + return 0; + } else if (log_page = i) { + log_start = log_size = 0; + return 0; + } + return -ENOMEM; + case 2: + if (!buf || len < 0) + return -EINVAL; + if (!len) + return 0; + verify_area(buf,len); + while (!log_size) { + if (!log_page) + return -EIO; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + cli(); + if (!log_size) + interruptible_sleep_on(&log_wait); + sti(); + } + i = 0; + while (log_size && len) { + c = *((char *) log_page+log_start); + log_start++; + log_size--; + log_start &= 4095; + put_fs_byte(c,buf); + buf++; + i++; + } + return i; + } + return -EINVAL; +} + int printk(const char *fmt, ...) { va_list args; - int i; + int i,j; + char * p; va_start(args, fmt); i=vsprintf(buf,fmt,args); va_end(args); + for (j = 0; j < i && log_page ; j++) { + p = (char *) log_page + (4095 & (log_start+log_size)); + *p = buf[j]; + if (log_size < 4096) + log_size++; + else + log_start++; + } + if (log_page) + wake_up(&log_wait); console_print(buf); return i; } |