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
23 #define LOG_BUF_LEN 4096
24
25 static char buf[1024];
26
27 extern int vsprintf(char * buf, const char * fmt, va_list args);
28 extern 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
33 unsigned long log_size = 0;
34 struct wait_queue * log_wait = NULL;
35 int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
36
37 static void (*console_print_proc)(const char *) = 0;
38 static char log_buf[LOG_BUF_LEN];
39 static unsigned long log_start = 0;
40 static 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 */
55 asmlinkage int sys_syslog(int type, char * buf, int len)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 < 0 || len > 8)
134 return -EINVAL;
135 console_loglevel = len;
136 return 0;
137 }
138 return -EINVAL;
139 }
140
141
142 asmlinkage int printk(const char *fmt, ...)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 logged_chars++;
180 if (*p == '\n')
181 break;
182 }
183 if (msg_level < console_loglevel && console_print_proc) {
184 char tmp = p[1];
185 p[1] = '\0';
186 (*console_print_proc)(msg);
187 p[1] = tmp;
188 }
189 if (*p == '\n')
190 msg_level = -1;
191 }
192 restore_flags(flags);
193 wake_up_interruptible(&log_wait);
194 return i;
195 }
196
197 /*
198 * The console driver calls this routine during kernel initialization
199 * to register the console printing procedure with printk() and to
200 * print any messages that were printed by the kernel before the
201 * console driver was initialized.
202 */
203 void register_console(void (*proc)(const char *))
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
204 {
205 int i,j;
206 int p = log_start;
207 char buf[16];
208 char msg_level = -1;
209 char *q;
210
211 console_print_proc = proc;
212
213 for (i=0,j=0; i < log_size; i++) {
214 buf[j++] = log_buf[p];
215 p++; p &= LOG_BUF_LEN-1;
216 if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
217 continue;
218 buf[j] = 0;
219 q = buf;
220 if (msg_level < 0) {
221 msg_level = buf[1] - '0';
222 q = buf + 3;
223 }
224 if (msg_level < console_loglevel)
225 (*proc)(q);
226 if (buf[j-1] == '\n')
227 msg_level = -1;
228 j = 0;
229 }
230 }