1
2
3
4
5
6
7
8
9
10
11
12
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
37#define DEFAULT_MESSAGE_LOGLEVEL 4
38
39
40#define MINIMUM_CONSOLE_LOGLEVEL 1
41#define DEFAULT_CONSOLE_LOGLEVEL 7
42
43unsigned long log_size = 0;
44struct wait_queue * log_wait = NULL;
45
46
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
59
60
61
62
63
64
65
66
67
68
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:
83 break;
84 case 1:
85 break;
86 case 2:
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:
121 do_clear = 1;
122
123 case 3:
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:
148 logged_chars = 0;
149 break;
150 case 6:
151 console_loglevel = minimum_console_loglevel;
152 break;
153 case 7:
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);
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
261
262
263
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
299
300
301
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