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 void console_print(const char *);
28
29 #define DEFAULT_MESSAGE_LOGLEVEL 7 /* KERN_DEBUG */
30 #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything more serious than KERN_DEBUG */
31
32 unsigned long log_size = 0;
33 struct wait_queue * log_wait = NULL;
34 int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
35
36 static void (*console_print_proc)(const char *) = 0;
37 static char log_buf[LOG_BUF_LEN];
38 static unsigned long log_start = 0;
39 static unsigned long logged_chars = 0;
40
41 /*
42 * Commands to sys_syslog:
43 *
44 * 0 -- Close the log. Currently a NOP.
45 * 1 -- Open the log. Currently a NOP.
46 * 2 -- Read from the log.
47 * 3 -- Read up to the last 4k of messages in the ring buffer.
48 * 4 -- Read and clear last 4k of messages in the ring buffer
49 * 5 -- Clear ring buffer.
50 * 6 -- Disable printk's to console
51 * 7 -- Enable printk's to console
52 * 8 -- Set level of messages printed to console
53 */
54 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)
*/
55 {
56 unsigned long i, j, count;
57 int do_clear = 0;
58 char c;
59 int error;
60
61 if ((type != 3) && !suser())
62 return -EPERM;
63 switch (type) {
64 case 0: /* Close log */
65 return 0;
66 case 1: /* Open log */
67 return 0;
68 case 2: /* Read from log */
69 if (!buf || len < 0)
70 return -EINVAL;
71 if (!len)
72 return 0;
73 error = verify_area(VERIFY_WRITE,buf,len);
74 if (error)
75 return error;
76 cli();
77 while (!log_size) {
78 if (current->signal & ~current->blocked) {
79 sti();
80 return -ERESTARTSYS;
81 }
82 interruptible_sleep_on(&log_wait);
83 }
84 i = 0;
85 while (log_size && i < len) {
86 c = *((char *) log_buf+log_start);
87 log_start++;
88 log_size--;
89 log_start &= LOG_BUF_LEN-1;
90 sti();
91 put_fs_byte(c,buf);
92 buf++;
93 i++;
94 cli();
95 }
96 sti();
97 return i;
98 case 4: /* Read/clear last kernel messages */
99 do_clear = 1;
100 /* FALL THRU */
101 case 3: /* Read last kernel messages */
102 if (!buf || len < 0)
103 return -EINVAL;
104 if (!len)
105 return 0;
106 error = verify_area(VERIFY_WRITE,buf,len);
107 if (error)
108 return error;
109 count = len;
110 if (count > LOG_BUF_LEN)
111 count = LOG_BUF_LEN;
112 if (count > logged_chars)
113 count = logged_chars;
114 j = log_start + log_size - count;
115 for (i = 0; i < count; i++) {
116 c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
117 put_fs_byte(c, buf++);
118 }
119 if (do_clear)
120 logged_chars = 0;
121 return i;
122 case 5: /* Clear ring buffer */
123 logged_chars = 0;
124 return 0;
125 case 6: /* Disable logging to console */
126 console_loglevel = 1; /* only panic messages shown */
127 return 0;
128 case 7: /* Enable logging to console */
129 console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
130 return 0;
131 case 8:
132 if (len < 0 || len > 8)
133 return -EINVAL;
134 console_loglevel = len;
135 return 0;
136 }
137 return -EINVAL;
138 }
139
140
141 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)
*/
142 {
143 va_list args;
144 int i;
145 char *msg, *p, *buf_end;
146 static char msg_level = -1;
147 long flags;
148
149 save_flags(flags);
150 cli();
151 va_start(args, fmt);
152 i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
153 buf_end = buf + 3 + i;
154 va_end(args);
155 for (p = buf + 3; p < buf_end; p++) {
156 msg = p;
157 if (msg_level < 0) {
158 if (
159 p[0] != '<' ||
160 p[1] < '0' ||
161 p[1] > '7' ||
162 p[2] != '>'
163 ) {
164 p -= 3;
165 p[0] = '<';
166 p[1] = DEFAULT_MESSAGE_LOGLEVEL - 1 + '0';
167 p[2] = '>';
168 } else
169 msg += 3;
170 msg_level = p[1] - '0';
171 }
172 for (; p < buf_end; p++) {
173 log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
174 if (log_size < LOG_BUF_LEN)
175 log_size++;
176 else
177 log_start++;
178 logged_chars++;
179 if (*p == '\n')
180 break;
181 }
182 if (msg_level < console_loglevel && console_print_proc) {
183 char tmp = p[1];
184 p[1] = '\0';
185 (*console_print_proc)(msg);
186 p[1] = tmp;
187 }
188 if (*p == '\n')
189 msg_level = -1;
190 }
191 restore_flags(flags);
192 wake_up_interruptible(&log_wait);
193 return i;
194 }
195
196 /*
197 * The console driver calls this routine during kernel initialization
198 * to register the console printing procedure with printk() and to
199 * print any messages that were printed by the kernel before the
200 * console driver was initialized.
201 */
202 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)
*/
203 {
204 int i,j;
205 int p = log_start;
206 char buf[16];
207 char msg_level = -1;
208 char *q;
209
210 console_print_proc = proc;
211
212 for (i=0,j=0; i < log_size; i++) {
213 buf[j++] = log_buf[p];
214 p++; p &= LOG_BUF_LEN-1;
215 if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
216 continue;
217 buf[j] = 0;
218 q = buf;
219 if (msg_level < 0) {
220 msg_level = buf[1] - '0';
221 q = buf + 3;
222 }
223 if (msg_level < console_loglevel)
224 (*proc)(q);
225 if (buf[j-1] == '\n')
226 msg_level = -1;
227 j = 0;
228 }
229 }