|
|
1.1 ! root 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 8192 ! 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 4 /* KERN_WARNING */ ! 34: ! 35: /* We show everything that is MORE important than this.. */ ! 36: #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ ! 37: #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ ! 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) ! 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, ...) ! 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 *)) ! 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) ! 249: { ! 250: if (tty && tty->driver.write) ! 251: tty->driver.write(tty, 0, msg, strlen(msg)); ! 252: return; ! 253: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.