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