Deleted Added
full compact
subr_prf.c (90490) subr_prf.c (91140)
1/*-
2 * Copyright (c) 1986, 1988, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
1/*-
2 * Copyright (c) 1986, 1988, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
39 * $FreeBSD: head/sys/kern/subr_prf.c 90490 2002-02-10 22:04:44Z phk $
39 * $FreeBSD: head/sys/kern/subr_prf.c 91140 2002-02-23 11:12:57Z tanimura $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/lock.h>
45#include <sys/mutex.h>
46#include <sys/sx.h>
44#include <sys/kernel.h>
45#include <sys/msgbuf.h>
46#include <sys/malloc.h>
47#include <sys/proc.h>
48#include <sys/sysctl.h>
49#include <sys/tty.h>
50#include <sys/syslog.h>
51#include <sys/cons.h>
52#include <sys/uio.h>
53
54/*
55 * Note that stdarg.h and the ANSI style va_start macro is used for both
56 * ANSI and traditional C compilers.
57 */
58#include <machine/stdarg.h>
59
60#define TOCONS 0x01
61#define TOTTY 0x02
62#define TOLOG 0x04
63
64/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
65#define MAXNBUF (sizeof(quad_t) * NBBY + 1)
66
67struct putchar_arg {
68 int flags;
69 int pri;
70 struct tty *tty;
71};
72
73struct snprintf_arg {
74 char *str;
75 size_t remain;
76};
77
78extern int log_open;
79
80struct tty *constty; /* pointer to console "window" tty */
81
82static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */
83static void msglogchar(int c, int pri);
84static void msgaddchar(int c, void *dummy);
85static void putchar __P((int ch, void *arg));
86static char *ksprintn __P((char *nbuf, u_long num, int base, int *len));
87static char *ksprintqn __P((char *nbuf, u_quad_t num, int base, int *len));
88static void snprintf_func __P((int ch, void *arg));
89
90static int consintr = 1; /* Ok to handle console interrupts? */
91static int msgbufmapped; /* Set when safe to use msgbuf */
92int msgbuftrigger;
93
94/*
95 * Warn that a system table is full.
96 */
97void
98tablefull(const char *tab)
99{
100
101 log(LOG_ERR, "%s: table is full\n", tab);
102}
103
104/*
105 * Uprintf prints to the controlling terminal for the current process.
106 * It may block if the tty queue is overfull. No message is printed if
107 * the queue does not clear in a reasonable time.
108 */
109int
110uprintf(const char *fmt, ...)
111{
112 struct thread *td = curthread;
113 struct proc *p = td->td_proc;
114 va_list ap;
115 struct putchar_arg pca;
47#include <sys/kernel.h>
48#include <sys/msgbuf.h>
49#include <sys/malloc.h>
50#include <sys/proc.h>
51#include <sys/sysctl.h>
52#include <sys/tty.h>
53#include <sys/syslog.h>
54#include <sys/cons.h>
55#include <sys/uio.h>
56
57/*
58 * Note that stdarg.h and the ANSI style va_start macro is used for both
59 * ANSI and traditional C compilers.
60 */
61#include <machine/stdarg.h>
62
63#define TOCONS 0x01
64#define TOTTY 0x02
65#define TOLOG 0x04
66
67/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
68#define MAXNBUF (sizeof(quad_t) * NBBY + 1)
69
70struct putchar_arg {
71 int flags;
72 int pri;
73 struct tty *tty;
74};
75
76struct snprintf_arg {
77 char *str;
78 size_t remain;
79};
80
81extern int log_open;
82
83struct tty *constty; /* pointer to console "window" tty */
84
85static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */
86static void msglogchar(int c, int pri);
87static void msgaddchar(int c, void *dummy);
88static void putchar __P((int ch, void *arg));
89static char *ksprintn __P((char *nbuf, u_long num, int base, int *len));
90static char *ksprintqn __P((char *nbuf, u_quad_t num, int base, int *len));
91static void snprintf_func __P((int ch, void *arg));
92
93static int consintr = 1; /* Ok to handle console interrupts? */
94static int msgbufmapped; /* Set when safe to use msgbuf */
95int msgbuftrigger;
96
97/*
98 * Warn that a system table is full.
99 */
100void
101tablefull(const char *tab)
102{
103
104 log(LOG_ERR, "%s: table is full\n", tab);
105}
106
107/*
108 * Uprintf prints to the controlling terminal for the current process.
109 * It may block if the tty queue is overfull. No message is printed if
110 * the queue does not clear in a reasonable time.
111 */
112int
113uprintf(const char *fmt, ...)
114{
115 struct thread *td = curthread;
116 struct proc *p = td->td_proc;
117 va_list ap;
118 struct putchar_arg pca;
116 int retval = 0;
119 int retval;
117
120
118 if (td && td != PCPU_GET(idlethread) && p->p_flag & P_CONTROLT &&
119 p->p_session->s_ttyvp) {
120 va_start(ap, fmt);
121 pca.tty = p->p_session->s_ttyp;
122 pca.flags = TOTTY;
123 retval = kvprintf(fmt, putchar, &pca, 10, ap);
124 va_end(ap);
121 if (td == NULL || td == PCPU_GET(idlethread))
122 return (0);
123
124 p = td->td_proc;
125 PROC_LOCK(p);
126 if ((p->p_flag & P_CONTROLT) == 0) {
127 PROC_UNLOCK(p);
128 return (0);
125 }
129 }
130 SESS_LOCK(p->p_session);
131 pca.tty = p->p_session->s_ttyp;
132 SESS_UNLOCK(p->p_session);
133 PROC_UNLOCK(p);
134 if (pca.tty == NULL)
135 return (0);
136 pca.flags = TOTTY;
137 va_start(ap, fmt);
138 retval = kvprintf(fmt, putchar, &pca, 10, ap);
139 va_end(ap);
140
126 return (retval);
127}
128
129/*
130 * tprintf prints on the controlling terminal associated
131 * with the given session, possibly to the log as well.
132 */
133void
134tprintf(struct proc *p, int pri, const char *fmt, ...)
135{
136 struct tty *tp = NULL;
137 int flags = 0, shld = 0;
138 va_list ap;
139 struct putchar_arg pca;
140 int retval;
141
142 if (pri != -1)
143 flags |= TOLOG;
141 return (retval);
142}
143
144/*
145 * tprintf prints on the controlling terminal associated
146 * with the given session, possibly to the log as well.
147 */
148void
149tprintf(struct proc *p, int pri, const char *fmt, ...)
150{
151 struct tty *tp = NULL;
152 int flags = 0, shld = 0;
153 va_list ap;
154 struct putchar_arg pca;
155 int retval;
156
157 if (pri != -1)
158 flags |= TOLOG;
144 if (p && p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
145 SESSHOLD(p->p_session);
146 shld++;
147 if (ttycheckoutq(p->p_session->s_ttyp, 0)) {
148 flags |= TOTTY;
159 if (p != NULL) {
160 PGRPSESS_XLOCK();
161 PROC_LOCK(p);
162 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
163 SESS_LOCK(p->p_session);
164 SESSHOLD(p->p_session);
149 tp = p->p_session->s_ttyp;
165 tp = p->p_session->s_ttyp;
150 }
166 SESS_UNLOCK(p->p_session);
167 PROC_UNLOCK(p);
168 shld++;
169 if (ttycheckoutq(tp, 0))
170 flags |= TOTTY;
171 else
172 tp = NULL;
173 } else
174 PROC_UNLOCK(p);
175 PGRPSESS_XUNLOCK();
151 }
152 pca.pri = pri;
153 pca.tty = tp;
154 pca.flags = flags;
155 va_start(ap, fmt);
156 retval = kvprintf(fmt, putchar, &pca, 10, ap);
157 va_end(ap);
176 }
177 pca.pri = pri;
178 pca.tty = tp;
179 pca.flags = flags;
180 va_start(ap, fmt);
181 retval = kvprintf(fmt, putchar, &pca, 10, ap);
182 va_end(ap);
158 if (shld)
183 if (shld) {
184 PGRPSESS_XLOCK();
185 SESS_LOCK(p->p_session);
159 SESSRELE(p->p_session);
186 SESSRELE(p->p_session);
187 SESS_UNLOCK(p->p_session);
188 PGRPSESS_XUNLOCK();
189 }
160 msgbuftrigger = 1;
161}
162
163/*
164 * Ttyprintf displays a message on a tty; it should be used only by
165 * the tty driver, or anything that knows the underlying tty will not
166 * be revoke(2)'d away. Other callers should use tprintf.
167 */
168int
169ttyprintf(struct tty *tp, const char *fmt, ...)
170{
171 va_list ap;
172 struct putchar_arg pca;
173 int retval;
174
175 va_start(ap, fmt);
176 pca.tty = tp;
177 pca.flags = TOTTY;
178 retval = kvprintf(fmt, putchar, &pca, 10, ap);
179 va_end(ap);
180 return (retval);
181}
182
183/*
184 * Log writes to the log buffer, and guarantees not to sleep (so can be
185 * called by interrupt routines). If there is no process reading the
186 * log yet, it writes to the console also.
187 */
188void
189log(int level, const char *fmt, ...)
190{
191 va_list ap;
192 int retval;
193 struct putchar_arg pca;
194
195 pca.tty = NULL;
196 pca.pri = level;
197 pca.flags = log_open ? TOLOG : TOCONS;
198
199 va_start(ap, fmt);
200 retval = kvprintf(fmt, putchar, &pca, 10, ap);
201 va_end(ap);
202
203 msgbuftrigger = 1;
204}
205
206#define CONSCHUNK 128
207
208void
209log_console(struct uio *uio)
210{
211 int c, i, error, iovlen, nl;
212 struct uio muio;
213 struct iovec *miov = NULL;
214 char *consbuffer;
215 int pri;
216
217 pri = LOG_INFO | LOG_CONSOLE;
218 muio = *uio;
219 iovlen = uio->uio_iovcnt * sizeof (struct iovec);
220 MALLOC(miov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
221 MALLOC(consbuffer, char *, CONSCHUNK, M_TEMP, M_WAITOK);
222 bcopy((caddr_t)muio.uio_iov, (caddr_t)miov, iovlen);
223 muio.uio_iov = miov;
224 uio = &muio;
225
226 nl = 0;
227 while (uio->uio_resid > 0) {
228 c = imin(uio->uio_resid, CONSCHUNK);
229 error = uiomove(consbuffer, c, uio);
230 if (error != 0)
231 return;
232 for (i = 0; i < c; i++) {
233 msglogchar(consbuffer[i], pri);
234 if (consbuffer[i] == '\n')
235 nl = 1;
236 else
237 nl = 0;
238 }
239 }
240 if (!nl)
241 msglogchar('\n', pri);
242 msgbuftrigger = 1;
243 FREE(miov, M_TEMP);
244 FREE(consbuffer, M_TEMP);
245 return;
246}
247
248int
249printf(const char *fmt, ...)
250{
251 va_list ap;
252 int savintr;
253 struct putchar_arg pca;
254 int retval;
255
256 savintr = consintr; /* disable interrupts */
257 consintr = 0;
258 va_start(ap, fmt);
259 pca.tty = NULL;
260 pca.flags = TOCONS | TOLOG;
261 pca.pri = -1;
262 retval = kvprintf(fmt, putchar, &pca, 10, ap);
263 va_end(ap);
264 if (!panicstr)
265 msgbuftrigger = 1;
266 consintr = savintr; /* reenable interrupts */
267 return (retval);
268}
269
270int
271vprintf(const char *fmt, va_list ap)
272{
273 int savintr;
274 struct putchar_arg pca;
275 int retval;
276
277 savintr = consintr; /* disable interrupts */
278 consintr = 0;
279 pca.tty = NULL;
280 pca.flags = TOCONS | TOLOG;
281 pca.pri = -1;
282 retval = kvprintf(fmt, putchar, &pca, 10, ap);
283 if (!panicstr)
284 msgbuftrigger = 1;
285 consintr = savintr; /* reenable interrupts */
286 return (retval);
287}
288
289/*
290 * Print a character on console or users terminal. If destination is
291 * the console then the last bunch of characters are saved in msgbuf for
292 * inspection later.
293 */
294static void
295putchar(int c, void *arg)
296{
297 struct putchar_arg *ap = (struct putchar_arg*) arg;
298 int flags = ap->flags;
299 struct tty *tp = ap->tty;
300 if (panicstr)
301 constty = NULL;
302 if ((flags & TOCONS) && tp == NULL && constty) {
303 tp = constty;
304 flags |= TOTTY;
305 }
306 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
307 (flags & TOCONS) && tp == constty)
308 constty = NULL;
309 if ((flags & TOLOG))
310 msglogchar(c, ap->pri);
311 if ((flags & TOCONS) && constty == NULL && c != '\0')
312 (*v_putc)(c);
313}
314
315/*
316 * Scaled down version of sprintf(3).
317 */
318int
319sprintf(char *buf, const char *cfmt, ...)
320{
321 int retval;
322 va_list ap;
323
324 va_start(ap, cfmt);
325 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
326 buf[retval] = '\0';
327 va_end(ap);
328 return (retval);
329}
330
331/*
332 * Scaled down version of vsprintf(3).
333 */
334int
335vsprintf(char *buf, const char *cfmt, va_list ap)
336{
337 int retval;
338
339 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
340 buf[retval] = '\0';
341 return (retval);
342}
343
344/*
345 * Scaled down version of snprintf(3).
346 */
347int
348snprintf(char *str, size_t size, const char *format, ...)
349{
350 int retval;
351 va_list ap;
352
353 va_start(ap, format);
354 retval = vsnprintf(str, size, format, ap);
355 va_end(ap);
356 return(retval);
357}
358
359/*
360 * Scaled down version of vsnprintf(3).
361 */
362int
363vsnprintf(char *str, size_t size, const char *format, va_list ap)
364{
365 struct snprintf_arg info;
366 int retval;
367
368 info.str = str;
369 info.remain = size;
370 retval = kvprintf(format, snprintf_func, &info, 10, ap);
371 if (info.remain >= 1)
372 *info.str++ = '\0';
373 return (retval);
374}
375
376static void
377snprintf_func(int ch, void *arg)
378{
379 struct snprintf_arg *const info = arg;
380
381 if (info->remain >= 2) {
382 *info->str++ = ch;
383 info->remain--;
384 }
385}
386
387/*
388 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
389 * order; return an optional length and a pointer to the last character
390 * written in the buffer (i.e., the first character of the string).
391 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
392 */
393static char *
394ksprintn(nbuf, ul, base, lenp)
395 char *nbuf;
396 u_long ul;
397 int base, *lenp;
398{
399 char *p;
400
401 p = nbuf;
402 *p = '\0';
403 do {
404 *++p = hex2ascii(ul % base);
405 } while (ul /= base);
406 if (lenp)
407 *lenp = p - nbuf;
408 return (p);
409}
410/* ksprintn, but for a quad_t. */
411static char *
412ksprintqn(nbuf, uq, base, lenp)
413 char *nbuf;
414 u_quad_t uq;
415 int base, *lenp;
416{
417 char *p;
418
419 p = nbuf;
420 *p = '\0';
421 do {
422 *++p = hex2ascii(uq % base);
423 } while (uq /= base);
424 if (lenp)
425 *lenp = p - nbuf;
426 return (p);
427}
428
429/*
430 * Scaled down version of printf(3).
431 *
432 * Two additional formats:
433 *
434 * The format %b is supported to decode error registers.
435 * Its usage is:
436 *
437 * printf("reg=%b\n", regval, "<base><arg>*");
438 *
439 * where <base> is the output base expressed as a control character, e.g.
440 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
441 * the first of which gives the bit number to be inspected (origin 1), and
442 * the next characters (up to a control character, i.e. a character <= 32),
443 * give the name of the register. Thus:
444 *
445 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
446 *
447 * would produce output:
448 *
449 * reg=3<BITTWO,BITONE>
450 *
451 * XXX: %D -- Hexdump, takes pointer and separator string:
452 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
453 * ("%*D", len, ptr, " " -> XX XX XX XX ...
454 */
455int
456kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
457{
458#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
459 char nbuf[MAXNBUF];
460 char *p, *q, *d;
461 u_char *up;
462 int ch, n;
463 u_long ul;
464 u_quad_t uq;
465 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
466 int dwidth;
467 char padc;
468 int retval = 0;
469
470 ul = 0;
471 uq = 0;
472 if (!func)
473 d = (char *) arg;
474 else
475 d = NULL;
476
477 if (fmt == NULL)
478 fmt = "(fmt null)\n";
479
480 if (radix < 2 || radix > 36)
481 radix = 10;
482
483 for (;;) {
484 padc = ' ';
485 width = 0;
486 while ((ch = (u_char)*fmt++) != '%') {
487 if (ch == '\0')
488 return (retval);
489 PCHAR(ch);
490 }
491 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
492 sign = 0; dot = 0; dwidth = 0;
493reswitch: switch (ch = (u_char)*fmt++) {
494 case '.':
495 dot = 1;
496 goto reswitch;
497 case '#':
498 sharpflag = 1;
499 goto reswitch;
500 case '+':
501 sign = 1;
502 goto reswitch;
503 case '-':
504 ladjust = 1;
505 goto reswitch;
506 case '%':
507 PCHAR(ch);
508 break;
509 case '*':
510 if (!dot) {
511 width = va_arg(ap, int);
512 if (width < 0) {
513 ladjust = !ladjust;
514 width = -width;
515 }
516 } else {
517 dwidth = va_arg(ap, int);
518 }
519 goto reswitch;
520 case '0':
521 if (!dot) {
522 padc = '0';
523 goto reswitch;
524 }
525 case '1': case '2': case '3': case '4':
526 case '5': case '6': case '7': case '8': case '9':
527 for (n = 0;; ++fmt) {
528 n = n * 10 + ch - '0';
529 ch = *fmt;
530 if (ch < '0' || ch > '9')
531 break;
532 }
533 if (dot)
534 dwidth = n;
535 else
536 width = n;
537 goto reswitch;
538 case 'b':
539 ul = va_arg(ap, int);
540 p = va_arg(ap, char *);
541 for (q = ksprintn(nbuf, ul, *p++, NULL); *q;)
542 PCHAR(*q--);
543
544 if (!ul)
545 break;
546
547 for (tmp = 0; *p;) {
548 n = *p++;
549 if (ul & (1 << (n - 1))) {
550 PCHAR(tmp ? ',' : '<');
551 for (; (n = *p) > ' '; ++p)
552 PCHAR(n);
553 tmp = 1;
554 } else
555 for (; *p > ' '; ++p)
556 continue;
557 }
558 if (tmp)
559 PCHAR('>');
560 break;
561 case 'c':
562 PCHAR(va_arg(ap, int));
563 break;
564 case 'D':
565 up = va_arg(ap, u_char *);
566 p = va_arg(ap, char *);
567 if (!width)
568 width = 16;
569 while(width--) {
570 PCHAR(hex2ascii(*up >> 4));
571 PCHAR(hex2ascii(*up & 0x0f));
572 up++;
573 if (width)
574 for (q=p;*q;q++)
575 PCHAR(*q);
576 }
577 break;
578 case 'd':
579 if (qflag)
580 uq = va_arg(ap, quad_t);
581 else if (lflag)
582 ul = va_arg(ap, long);
583 else
584 ul = va_arg(ap, int);
585 sign = 1;
586 base = 10;
587 goto number;
588 case 'l':
589 if (lflag) {
590 lflag = 0;
591 qflag = 1;
592 } else
593 lflag = 1;
594 goto reswitch;
595 case 'o':
596 if (qflag)
597 uq = va_arg(ap, u_quad_t);
598 else if (lflag)
599 ul = va_arg(ap, u_long);
600 else
601 ul = va_arg(ap, u_int);
602 base = 8;
603 goto nosign;
604 case 'p':
605 ul = (uintptr_t)va_arg(ap, void *);
606 base = 16;
607 sharpflag = (width == 0);
608 goto nosign;
609 case 'q':
610 qflag = 1;
611 goto reswitch;
612 case 'n':
613 case 'r':
614 if (qflag)
615 uq = va_arg(ap, u_quad_t);
616 else if (lflag)
617 ul = va_arg(ap, u_long);
618 else
619 ul = sign ?
620 (u_long)va_arg(ap, int) : va_arg(ap, u_int);
621 base = radix;
622 goto number;
623 case 's':
624 p = va_arg(ap, char *);
625 if (p == NULL)
626 p = "(null)";
627 if (!dot)
628 n = strlen (p);
629 else
630 for (n = 0; n < dwidth && p[n]; n++)
631 continue;
632
633 width -= n;
634
635 if (!ladjust && width > 0)
636 while (width--)
637 PCHAR(padc);
638 while (n--)
639 PCHAR(*p++);
640 if (ladjust && width > 0)
641 while (width--)
642 PCHAR(padc);
643 break;
644 case 'u':
645 if (qflag)
646 uq = va_arg(ap, u_quad_t);
647 else if (lflag)
648 ul = va_arg(ap, u_long);
649 else
650 ul = va_arg(ap, u_int);
651 base = 10;
652 goto nosign;
653 case 'x':
654 case 'X':
655 if (qflag)
656 uq = va_arg(ap, u_quad_t);
657 else if (lflag)
658 ul = va_arg(ap, u_long);
659 else
660 ul = va_arg(ap, u_int);
661 base = 16;
662 goto nosign;
663 case 'z':
664 if (qflag)
665 uq = va_arg(ap, u_quad_t);
666 else if (lflag)
667 ul = va_arg(ap, u_long);
668 else
669 ul = sign ?
670 (u_long)va_arg(ap, int) : va_arg(ap, u_int);
671 base = 16;
672 goto number;
673nosign: sign = 0;
674number:
675 if (qflag) {
676 if (sign && (quad_t)uq < 0) {
677 neg = 1;
678 uq = -(quad_t)uq;
679 }
680 p = ksprintqn(nbuf, uq, base, &tmp);
681 } else {
682 if (sign && (long)ul < 0) {
683 neg = 1;
684 ul = -(long)ul;
685 }
686 p = ksprintn(nbuf, ul, base, &tmp);
687 }
688 if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
689 if (base == 8)
690 tmp++;
691 else if (base == 16)
692 tmp += 2;
693 }
694 if (neg)
695 tmp++;
696
697 if (!ladjust && width && (width -= tmp) > 0)
698 while (width--)
699 PCHAR(padc);
700 if (neg)
701 PCHAR('-');
702 if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
703 if (base == 8) {
704 PCHAR('0');
705 } else if (base == 16) {
706 PCHAR('0');
707 PCHAR('x');
708 }
709 }
710
711 while (*p)
712 PCHAR(*p--);
713
714 if (ladjust && width && (width -= tmp) > 0)
715 while (width--)
716 PCHAR(padc);
717
718 break;
719 default:
720 PCHAR('%');
721 if (lflag)
722 PCHAR('l');
723 PCHAR(ch);
724 break;
725 }
726 }
727#undef PCHAR
728}
729
730/*
731 * Put character in log buffer with a particular priority.
732 */
733static void
734msglogchar(int c, int pri)
735{
736 static int lastpri = -1;
737 static int dangling;
738 char nbuf[MAXNBUF];
739 char *p;
740
741 if (!msgbufmapped)
742 return;
743 if (c == '\0' || c == '\r')
744 return;
745 if (pri != -1 && pri != lastpri) {
746 if (dangling) {
747 msgaddchar('\n', NULL);
748 dangling = 0;
749 }
750 msgaddchar('<', NULL);
751 for (p = ksprintn(nbuf, (u_long)pri, 10, NULL); *p;)
752 msgaddchar(*p--, NULL);
753 msgaddchar('>', NULL);
754 lastpri = pri;
755 }
756 msgaddchar(c, NULL);
757 if (c == '\n') {
758 dangling = 0;
759 lastpri = -1;
760 } else {
761 dangling = 1;
762 }
763}
764
765/*
766 * Put char in log buffer
767 */
768static void
769msgaddchar(int c, void *dummy)
770{
771 struct msgbuf *mbp;
772
773 if (!msgbufmapped)
774 return;
775 mbp = msgbufp;
776 mbp->msg_ptr[mbp->msg_bufx++] = c;
777 if (mbp->msg_bufx >= mbp->msg_size)
778 mbp->msg_bufx = 0;
779 /* If the buffer is full, keep the most recent data. */
780 if (mbp->msg_bufr == mbp->msg_bufx) {
781 if (++mbp->msg_bufr >= mbp->msg_size)
782 mbp->msg_bufr = 0;
783 }
784}
785
786static void
787msgbufcopy(struct msgbuf *oldp)
788{
789 int pos;
790
791 pos = oldp->msg_bufr;
792 while (pos != oldp->msg_bufx) {
793 msglogchar(oldp->msg_ptr[pos], -1);
794 if (++pos >= oldp->msg_size)
795 pos = 0;
796 }
797}
798
799void
800msgbufinit(void *ptr, size_t size)
801{
802 char *cp;
803 static struct msgbuf *oldp = NULL;
804
805 size -= sizeof(*msgbufp);
806 cp = (char *)ptr;
807 msgbufp = (struct msgbuf *) (cp + size);
808 if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_size != size ||
809 msgbufp->msg_bufx >= size || msgbufp->msg_bufr >= size) {
810 bzero(cp, size);
811 bzero(msgbufp, sizeof(*msgbufp));
812 msgbufp->msg_magic = MSG_MAGIC;
813 msgbufp->msg_size = (char *)msgbufp - cp;
814 }
815 msgbufp->msg_ptr = cp;
816 if (msgbufmapped && oldp != msgbufp)
817 msgbufcopy(oldp);
818 msgbufmapped = 1;
819 oldp = msgbufp;
820}
821
822SYSCTL_DECL(_security_bsd);
823
824static int unprivileged_read_msgbuf = 1;
825SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
826 CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
827 "Unprivileged processes may read the kernel message buffer");
828
829/* Sysctls for accessing/clearing the msgbuf */
830static int
831sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
832{
833 int error;
834
835 if (!unprivileged_read_msgbuf) {
836 error = suser_td(req->td);
837 if (error)
838 return (error);
839 }
840
841 /*
842 * Unwind the buffer, so that it's linear (possibly starting with
843 * some initial nulls).
844 */
845 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr + msgbufp->msg_bufx,
846 msgbufp->msg_size - msgbufp->msg_bufx, req);
847 if (error)
848 return (error);
849 if (msgbufp->msg_bufx > 0) {
850 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr,
851 msgbufp->msg_bufx, req);
852 }
853 return (error);
854}
855
856SYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD,
857 0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
858
859static int msgbuf_clear;
860
861static int
862sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
863{
864 int error;
865 error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
866 if (!error && req->newptr) {
867 /* Clear the buffer and reset write pointer */
868 bzero(msgbufp->msg_ptr, msgbufp->msg_size);
869 msgbufp->msg_bufr = msgbufp->msg_bufx = 0;
870 msgbuf_clear = 0;
871 }
872 return (error);
873}
874
875SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
876 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clear, 0,
877 sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer");
878
879#include "opt_ddb.h"
880#ifdef DDB
881#include <ddb/ddb.h>
882
883DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
884{
885 int i, j;
886
887 if (!msgbufmapped) {
888 db_printf("msgbuf not mapped yet\n");
889 return;
890 }
891 db_printf("msgbufp = %p\n", msgbufp);
892 db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
893 msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
894 msgbufp->msg_bufx, msgbufp->msg_ptr);
895 for (i = 0; i < msgbufp->msg_size; i++) {
896 j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
897 db_printf("%c", msgbufp->msg_ptr[j]);
898 }
899 db_printf("\n");
900}
901
902#endif /* DDB */
190 msgbuftrigger = 1;
191}
192
193/*
194 * Ttyprintf displays a message on a tty; it should be used only by
195 * the tty driver, or anything that knows the underlying tty will not
196 * be revoke(2)'d away. Other callers should use tprintf.
197 */
198int
199ttyprintf(struct tty *tp, const char *fmt, ...)
200{
201 va_list ap;
202 struct putchar_arg pca;
203 int retval;
204
205 va_start(ap, fmt);
206 pca.tty = tp;
207 pca.flags = TOTTY;
208 retval = kvprintf(fmt, putchar, &pca, 10, ap);
209 va_end(ap);
210 return (retval);
211}
212
213/*
214 * Log writes to the log buffer, and guarantees not to sleep (so can be
215 * called by interrupt routines). If there is no process reading the
216 * log yet, it writes to the console also.
217 */
218void
219log(int level, const char *fmt, ...)
220{
221 va_list ap;
222 int retval;
223 struct putchar_arg pca;
224
225 pca.tty = NULL;
226 pca.pri = level;
227 pca.flags = log_open ? TOLOG : TOCONS;
228
229 va_start(ap, fmt);
230 retval = kvprintf(fmt, putchar, &pca, 10, ap);
231 va_end(ap);
232
233 msgbuftrigger = 1;
234}
235
236#define CONSCHUNK 128
237
238void
239log_console(struct uio *uio)
240{
241 int c, i, error, iovlen, nl;
242 struct uio muio;
243 struct iovec *miov = NULL;
244 char *consbuffer;
245 int pri;
246
247 pri = LOG_INFO | LOG_CONSOLE;
248 muio = *uio;
249 iovlen = uio->uio_iovcnt * sizeof (struct iovec);
250 MALLOC(miov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
251 MALLOC(consbuffer, char *, CONSCHUNK, M_TEMP, M_WAITOK);
252 bcopy((caddr_t)muio.uio_iov, (caddr_t)miov, iovlen);
253 muio.uio_iov = miov;
254 uio = &muio;
255
256 nl = 0;
257 while (uio->uio_resid > 0) {
258 c = imin(uio->uio_resid, CONSCHUNK);
259 error = uiomove(consbuffer, c, uio);
260 if (error != 0)
261 return;
262 for (i = 0; i < c; i++) {
263 msglogchar(consbuffer[i], pri);
264 if (consbuffer[i] == '\n')
265 nl = 1;
266 else
267 nl = 0;
268 }
269 }
270 if (!nl)
271 msglogchar('\n', pri);
272 msgbuftrigger = 1;
273 FREE(miov, M_TEMP);
274 FREE(consbuffer, M_TEMP);
275 return;
276}
277
278int
279printf(const char *fmt, ...)
280{
281 va_list ap;
282 int savintr;
283 struct putchar_arg pca;
284 int retval;
285
286 savintr = consintr; /* disable interrupts */
287 consintr = 0;
288 va_start(ap, fmt);
289 pca.tty = NULL;
290 pca.flags = TOCONS | TOLOG;
291 pca.pri = -1;
292 retval = kvprintf(fmt, putchar, &pca, 10, ap);
293 va_end(ap);
294 if (!panicstr)
295 msgbuftrigger = 1;
296 consintr = savintr; /* reenable interrupts */
297 return (retval);
298}
299
300int
301vprintf(const char *fmt, va_list ap)
302{
303 int savintr;
304 struct putchar_arg pca;
305 int retval;
306
307 savintr = consintr; /* disable interrupts */
308 consintr = 0;
309 pca.tty = NULL;
310 pca.flags = TOCONS | TOLOG;
311 pca.pri = -1;
312 retval = kvprintf(fmt, putchar, &pca, 10, ap);
313 if (!panicstr)
314 msgbuftrigger = 1;
315 consintr = savintr; /* reenable interrupts */
316 return (retval);
317}
318
319/*
320 * Print a character on console or users terminal. If destination is
321 * the console then the last bunch of characters are saved in msgbuf for
322 * inspection later.
323 */
324static void
325putchar(int c, void *arg)
326{
327 struct putchar_arg *ap = (struct putchar_arg*) arg;
328 int flags = ap->flags;
329 struct tty *tp = ap->tty;
330 if (panicstr)
331 constty = NULL;
332 if ((flags & TOCONS) && tp == NULL && constty) {
333 tp = constty;
334 flags |= TOTTY;
335 }
336 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
337 (flags & TOCONS) && tp == constty)
338 constty = NULL;
339 if ((flags & TOLOG))
340 msglogchar(c, ap->pri);
341 if ((flags & TOCONS) && constty == NULL && c != '\0')
342 (*v_putc)(c);
343}
344
345/*
346 * Scaled down version of sprintf(3).
347 */
348int
349sprintf(char *buf, const char *cfmt, ...)
350{
351 int retval;
352 va_list ap;
353
354 va_start(ap, cfmt);
355 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
356 buf[retval] = '\0';
357 va_end(ap);
358 return (retval);
359}
360
361/*
362 * Scaled down version of vsprintf(3).
363 */
364int
365vsprintf(char *buf, const char *cfmt, va_list ap)
366{
367 int retval;
368
369 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
370 buf[retval] = '\0';
371 return (retval);
372}
373
374/*
375 * Scaled down version of snprintf(3).
376 */
377int
378snprintf(char *str, size_t size, const char *format, ...)
379{
380 int retval;
381 va_list ap;
382
383 va_start(ap, format);
384 retval = vsnprintf(str, size, format, ap);
385 va_end(ap);
386 return(retval);
387}
388
389/*
390 * Scaled down version of vsnprintf(3).
391 */
392int
393vsnprintf(char *str, size_t size, const char *format, va_list ap)
394{
395 struct snprintf_arg info;
396 int retval;
397
398 info.str = str;
399 info.remain = size;
400 retval = kvprintf(format, snprintf_func, &info, 10, ap);
401 if (info.remain >= 1)
402 *info.str++ = '\0';
403 return (retval);
404}
405
406static void
407snprintf_func(int ch, void *arg)
408{
409 struct snprintf_arg *const info = arg;
410
411 if (info->remain >= 2) {
412 *info->str++ = ch;
413 info->remain--;
414 }
415}
416
417/*
418 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
419 * order; return an optional length and a pointer to the last character
420 * written in the buffer (i.e., the first character of the string).
421 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
422 */
423static char *
424ksprintn(nbuf, ul, base, lenp)
425 char *nbuf;
426 u_long ul;
427 int base, *lenp;
428{
429 char *p;
430
431 p = nbuf;
432 *p = '\0';
433 do {
434 *++p = hex2ascii(ul % base);
435 } while (ul /= base);
436 if (lenp)
437 *lenp = p - nbuf;
438 return (p);
439}
440/* ksprintn, but for a quad_t. */
441static char *
442ksprintqn(nbuf, uq, base, lenp)
443 char *nbuf;
444 u_quad_t uq;
445 int base, *lenp;
446{
447 char *p;
448
449 p = nbuf;
450 *p = '\0';
451 do {
452 *++p = hex2ascii(uq % base);
453 } while (uq /= base);
454 if (lenp)
455 *lenp = p - nbuf;
456 return (p);
457}
458
459/*
460 * Scaled down version of printf(3).
461 *
462 * Two additional formats:
463 *
464 * The format %b is supported to decode error registers.
465 * Its usage is:
466 *
467 * printf("reg=%b\n", regval, "<base><arg>*");
468 *
469 * where <base> is the output base expressed as a control character, e.g.
470 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
471 * the first of which gives the bit number to be inspected (origin 1), and
472 * the next characters (up to a control character, i.e. a character <= 32),
473 * give the name of the register. Thus:
474 *
475 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
476 *
477 * would produce output:
478 *
479 * reg=3<BITTWO,BITONE>
480 *
481 * XXX: %D -- Hexdump, takes pointer and separator string:
482 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
483 * ("%*D", len, ptr, " " -> XX XX XX XX ...
484 */
485int
486kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
487{
488#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
489 char nbuf[MAXNBUF];
490 char *p, *q, *d;
491 u_char *up;
492 int ch, n;
493 u_long ul;
494 u_quad_t uq;
495 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
496 int dwidth;
497 char padc;
498 int retval = 0;
499
500 ul = 0;
501 uq = 0;
502 if (!func)
503 d = (char *) arg;
504 else
505 d = NULL;
506
507 if (fmt == NULL)
508 fmt = "(fmt null)\n";
509
510 if (radix < 2 || radix > 36)
511 radix = 10;
512
513 for (;;) {
514 padc = ' ';
515 width = 0;
516 while ((ch = (u_char)*fmt++) != '%') {
517 if (ch == '\0')
518 return (retval);
519 PCHAR(ch);
520 }
521 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
522 sign = 0; dot = 0; dwidth = 0;
523reswitch: switch (ch = (u_char)*fmt++) {
524 case '.':
525 dot = 1;
526 goto reswitch;
527 case '#':
528 sharpflag = 1;
529 goto reswitch;
530 case '+':
531 sign = 1;
532 goto reswitch;
533 case '-':
534 ladjust = 1;
535 goto reswitch;
536 case '%':
537 PCHAR(ch);
538 break;
539 case '*':
540 if (!dot) {
541 width = va_arg(ap, int);
542 if (width < 0) {
543 ladjust = !ladjust;
544 width = -width;
545 }
546 } else {
547 dwidth = va_arg(ap, int);
548 }
549 goto reswitch;
550 case '0':
551 if (!dot) {
552 padc = '0';
553 goto reswitch;
554 }
555 case '1': case '2': case '3': case '4':
556 case '5': case '6': case '7': case '8': case '9':
557 for (n = 0;; ++fmt) {
558 n = n * 10 + ch - '0';
559 ch = *fmt;
560 if (ch < '0' || ch > '9')
561 break;
562 }
563 if (dot)
564 dwidth = n;
565 else
566 width = n;
567 goto reswitch;
568 case 'b':
569 ul = va_arg(ap, int);
570 p = va_arg(ap, char *);
571 for (q = ksprintn(nbuf, ul, *p++, NULL); *q;)
572 PCHAR(*q--);
573
574 if (!ul)
575 break;
576
577 for (tmp = 0; *p;) {
578 n = *p++;
579 if (ul & (1 << (n - 1))) {
580 PCHAR(tmp ? ',' : '<');
581 for (; (n = *p) > ' '; ++p)
582 PCHAR(n);
583 tmp = 1;
584 } else
585 for (; *p > ' '; ++p)
586 continue;
587 }
588 if (tmp)
589 PCHAR('>');
590 break;
591 case 'c':
592 PCHAR(va_arg(ap, int));
593 break;
594 case 'D':
595 up = va_arg(ap, u_char *);
596 p = va_arg(ap, char *);
597 if (!width)
598 width = 16;
599 while(width--) {
600 PCHAR(hex2ascii(*up >> 4));
601 PCHAR(hex2ascii(*up & 0x0f));
602 up++;
603 if (width)
604 for (q=p;*q;q++)
605 PCHAR(*q);
606 }
607 break;
608 case 'd':
609 if (qflag)
610 uq = va_arg(ap, quad_t);
611 else if (lflag)
612 ul = va_arg(ap, long);
613 else
614 ul = va_arg(ap, int);
615 sign = 1;
616 base = 10;
617 goto number;
618 case 'l':
619 if (lflag) {
620 lflag = 0;
621 qflag = 1;
622 } else
623 lflag = 1;
624 goto reswitch;
625 case 'o':
626 if (qflag)
627 uq = va_arg(ap, u_quad_t);
628 else if (lflag)
629 ul = va_arg(ap, u_long);
630 else
631 ul = va_arg(ap, u_int);
632 base = 8;
633 goto nosign;
634 case 'p':
635 ul = (uintptr_t)va_arg(ap, void *);
636 base = 16;
637 sharpflag = (width == 0);
638 goto nosign;
639 case 'q':
640 qflag = 1;
641 goto reswitch;
642 case 'n':
643 case 'r':
644 if (qflag)
645 uq = va_arg(ap, u_quad_t);
646 else if (lflag)
647 ul = va_arg(ap, u_long);
648 else
649 ul = sign ?
650 (u_long)va_arg(ap, int) : va_arg(ap, u_int);
651 base = radix;
652 goto number;
653 case 's':
654 p = va_arg(ap, char *);
655 if (p == NULL)
656 p = "(null)";
657 if (!dot)
658 n = strlen (p);
659 else
660 for (n = 0; n < dwidth && p[n]; n++)
661 continue;
662
663 width -= n;
664
665 if (!ladjust && width > 0)
666 while (width--)
667 PCHAR(padc);
668 while (n--)
669 PCHAR(*p++);
670 if (ladjust && width > 0)
671 while (width--)
672 PCHAR(padc);
673 break;
674 case 'u':
675 if (qflag)
676 uq = va_arg(ap, u_quad_t);
677 else if (lflag)
678 ul = va_arg(ap, u_long);
679 else
680 ul = va_arg(ap, u_int);
681 base = 10;
682 goto nosign;
683 case 'x':
684 case 'X':
685 if (qflag)
686 uq = va_arg(ap, u_quad_t);
687 else if (lflag)
688 ul = va_arg(ap, u_long);
689 else
690 ul = va_arg(ap, u_int);
691 base = 16;
692 goto nosign;
693 case 'z':
694 if (qflag)
695 uq = va_arg(ap, u_quad_t);
696 else if (lflag)
697 ul = va_arg(ap, u_long);
698 else
699 ul = sign ?
700 (u_long)va_arg(ap, int) : va_arg(ap, u_int);
701 base = 16;
702 goto number;
703nosign: sign = 0;
704number:
705 if (qflag) {
706 if (sign && (quad_t)uq < 0) {
707 neg = 1;
708 uq = -(quad_t)uq;
709 }
710 p = ksprintqn(nbuf, uq, base, &tmp);
711 } else {
712 if (sign && (long)ul < 0) {
713 neg = 1;
714 ul = -(long)ul;
715 }
716 p = ksprintn(nbuf, ul, base, &tmp);
717 }
718 if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
719 if (base == 8)
720 tmp++;
721 else if (base == 16)
722 tmp += 2;
723 }
724 if (neg)
725 tmp++;
726
727 if (!ladjust && width && (width -= tmp) > 0)
728 while (width--)
729 PCHAR(padc);
730 if (neg)
731 PCHAR('-');
732 if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
733 if (base == 8) {
734 PCHAR('0');
735 } else if (base == 16) {
736 PCHAR('0');
737 PCHAR('x');
738 }
739 }
740
741 while (*p)
742 PCHAR(*p--);
743
744 if (ladjust && width && (width -= tmp) > 0)
745 while (width--)
746 PCHAR(padc);
747
748 break;
749 default:
750 PCHAR('%');
751 if (lflag)
752 PCHAR('l');
753 PCHAR(ch);
754 break;
755 }
756 }
757#undef PCHAR
758}
759
760/*
761 * Put character in log buffer with a particular priority.
762 */
763static void
764msglogchar(int c, int pri)
765{
766 static int lastpri = -1;
767 static int dangling;
768 char nbuf[MAXNBUF];
769 char *p;
770
771 if (!msgbufmapped)
772 return;
773 if (c == '\0' || c == '\r')
774 return;
775 if (pri != -1 && pri != lastpri) {
776 if (dangling) {
777 msgaddchar('\n', NULL);
778 dangling = 0;
779 }
780 msgaddchar('<', NULL);
781 for (p = ksprintn(nbuf, (u_long)pri, 10, NULL); *p;)
782 msgaddchar(*p--, NULL);
783 msgaddchar('>', NULL);
784 lastpri = pri;
785 }
786 msgaddchar(c, NULL);
787 if (c == '\n') {
788 dangling = 0;
789 lastpri = -1;
790 } else {
791 dangling = 1;
792 }
793}
794
795/*
796 * Put char in log buffer
797 */
798static void
799msgaddchar(int c, void *dummy)
800{
801 struct msgbuf *mbp;
802
803 if (!msgbufmapped)
804 return;
805 mbp = msgbufp;
806 mbp->msg_ptr[mbp->msg_bufx++] = c;
807 if (mbp->msg_bufx >= mbp->msg_size)
808 mbp->msg_bufx = 0;
809 /* If the buffer is full, keep the most recent data. */
810 if (mbp->msg_bufr == mbp->msg_bufx) {
811 if (++mbp->msg_bufr >= mbp->msg_size)
812 mbp->msg_bufr = 0;
813 }
814}
815
816static void
817msgbufcopy(struct msgbuf *oldp)
818{
819 int pos;
820
821 pos = oldp->msg_bufr;
822 while (pos != oldp->msg_bufx) {
823 msglogchar(oldp->msg_ptr[pos], -1);
824 if (++pos >= oldp->msg_size)
825 pos = 0;
826 }
827}
828
829void
830msgbufinit(void *ptr, size_t size)
831{
832 char *cp;
833 static struct msgbuf *oldp = NULL;
834
835 size -= sizeof(*msgbufp);
836 cp = (char *)ptr;
837 msgbufp = (struct msgbuf *) (cp + size);
838 if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_size != size ||
839 msgbufp->msg_bufx >= size || msgbufp->msg_bufr >= size) {
840 bzero(cp, size);
841 bzero(msgbufp, sizeof(*msgbufp));
842 msgbufp->msg_magic = MSG_MAGIC;
843 msgbufp->msg_size = (char *)msgbufp - cp;
844 }
845 msgbufp->msg_ptr = cp;
846 if (msgbufmapped && oldp != msgbufp)
847 msgbufcopy(oldp);
848 msgbufmapped = 1;
849 oldp = msgbufp;
850}
851
852SYSCTL_DECL(_security_bsd);
853
854static int unprivileged_read_msgbuf = 1;
855SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
856 CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
857 "Unprivileged processes may read the kernel message buffer");
858
859/* Sysctls for accessing/clearing the msgbuf */
860static int
861sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
862{
863 int error;
864
865 if (!unprivileged_read_msgbuf) {
866 error = suser_td(req->td);
867 if (error)
868 return (error);
869 }
870
871 /*
872 * Unwind the buffer, so that it's linear (possibly starting with
873 * some initial nulls).
874 */
875 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr + msgbufp->msg_bufx,
876 msgbufp->msg_size - msgbufp->msg_bufx, req);
877 if (error)
878 return (error);
879 if (msgbufp->msg_bufx > 0) {
880 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr,
881 msgbufp->msg_bufx, req);
882 }
883 return (error);
884}
885
886SYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD,
887 0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
888
889static int msgbuf_clear;
890
891static int
892sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
893{
894 int error;
895 error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
896 if (!error && req->newptr) {
897 /* Clear the buffer and reset write pointer */
898 bzero(msgbufp->msg_ptr, msgbufp->msg_size);
899 msgbufp->msg_bufr = msgbufp->msg_bufx = 0;
900 msgbuf_clear = 0;
901 }
902 return (error);
903}
904
905SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
906 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clear, 0,
907 sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer");
908
909#include "opt_ddb.h"
910#ifdef DDB
911#include <ddb/ddb.h>
912
913DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
914{
915 int i, j;
916
917 if (!msgbufmapped) {
918 db_printf("msgbuf not mapped yet\n");
919 return;
920 }
921 db_printf("msgbufp = %p\n", msgbufp);
922 db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
923 msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
924 msgbufp->msg_bufx, msgbufp->msg_ptr);
925 for (i = 0; i < msgbufp->msg_size; i++) {
926 j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
927 db_printf("%c", msgbufp->msg_ptr[j]);
928 }
929 db_printf("\n");
930}
931
932#endif /* DDB */