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