source: rtems-libbsd/freebsd/sys/kern/subr_prf.c @ 5268338

5-freebsd-12
Last change on this file since 5268338 was 5268338, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 6, 2017 at 11:06:19 AM

Provide sbuf_hexdump()

  • Property mode set to 100644
File size: 26.8 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 1986, 1988, 1991, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *      @(#)subr_prf.c  8.3 (Berkeley) 1/21/94
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD$");
41
42#ifdef _KERNEL
43#include <rtems/bsd/local/opt_ddb.h>
44#include <rtems/bsd/local/opt_printf.h>
45#endif  /* _KERNEL */
46
47#include <rtems/bsd/sys/param.h>
48#ifdef _KERNEL
49#include <sys/systm.h>
50#include <rtems/bsd/sys/lock.h>
51#include <sys/kdb.h>
52#include <sys/mutex.h>
53#include <sys/sx.h>
54#include <sys/kernel.h>
55#ifndef __rtems__
56#include <sys/msgbuf.h>
57#endif /* __rtems__ */
58#include <sys/malloc.h>
59#include <sys/priv.h>
60#include <sys/proc.h>
61#include <sys/stddef.h>
62#include <sys/sysctl.h>
63#ifndef __rtems__
64#include <sys/tty.h>
65#endif /* __rtems__ */
66#include <sys/syslog.h>
67#ifndef __rtems__
68#include <sys/cons.h>
69#endif /* __rtems__ */
70#include <sys/uio.h>
71#endif
72#include <sys/ctype.h>
73#include <sys/sbuf.h>
74
75#ifdef DDB
76#include <ddb/ddb.h>
77#endif
78
79/*
80 * Note that stdarg.h and the ANSI style va_start macro is used for both
81 * ANSI and traditional C compilers.
82 */
83#ifdef _KERNEL
84#include <machine/stdarg.h>
85#else
86#include <stdarg.h>
87#endif
88
89#ifdef _KERNEL
90
91#ifndef __rtems__
92#define TOCONS  0x01
93#define TOTTY   0x02
94#define TOLOG   0x04
95#endif /* __rtems__ */
96
97/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
98#define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
99
100#ifndef __rtems__
101struct putchar_arg {
102        int     flags;
103        int     pri;
104        struct  tty *tty;
105        char    *p_bufr;
106        size_t  n_bufr;
107        char    *p_next;
108        size_t  remain;
109};
110#endif /* __rtems__ */
111
112struct snprintf_arg {
113        char    *str;
114        size_t  remain;
115};
116
117#ifndef __rtems__
118extern  int log_open;
119
120static void  msglogchar(int c, int pri);
121static void  msglogstr(char *str, int pri, int filter_cr);
122static void  putchar(int ch, void *arg);
123#endif /* __rtems__ */
124static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
125static void  snprintf_func(int ch, void *arg);
126
127#ifndef __rtems__
128static int msgbufmapped;                /* Set when safe to use msgbuf */
129int msgbuftrigger;
130
131static int log_console_output = 1;
132SYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RWTUN,
133    &log_console_output, 0, "Duplicate console output to the syslog");
134
135/*
136 * See the comment in log_console() below for more explanation of this.
137 */
138static int log_console_add_linefeed;
139SYSCTL_INT(_kern, OID_AUTO, log_console_add_linefeed, CTLFLAG_RWTUN,
140    &log_console_add_linefeed, 0, "log_console() adds extra newlines");
141
142static int always_console_output;
143SYSCTL_INT(_kern, OID_AUTO, always_console_output, CTLFLAG_RWTUN,
144    &always_console_output, 0, "Always output to console despite TIOCCONS");
145
146/*
147 * Warn that a system table is full.
148 */
149void
150tablefull(const char *tab)
151{
152
153        log(LOG_ERR, "%s: table is full\n", tab);
154}
155
156/*
157 * Uprintf prints to the controlling terminal for the current process.
158 */
159int
160uprintf(const char *fmt, ...)
161{
162        va_list ap;
163        struct putchar_arg pca;
164        struct proc *p;
165        struct thread *td;
166        int retval;
167
168        td = curthread;
169        if (TD_IS_IDLETHREAD(td))
170                return (0);
171
172        sx_slock(&proctree_lock);
173        p = td->td_proc;
174        PROC_LOCK(p);
175        if ((p->p_flag & P_CONTROLT) == 0) {
176                PROC_UNLOCK(p);
177                sx_sunlock(&proctree_lock);
178                return (0);
179        }
180        SESS_LOCK(p->p_session);
181        pca.tty = p->p_session->s_ttyp;
182        SESS_UNLOCK(p->p_session);
183        PROC_UNLOCK(p);
184        if (pca.tty == NULL) {
185                sx_sunlock(&proctree_lock);
186                return (0);
187        }
188        pca.flags = TOTTY;
189        pca.p_bufr = NULL;
190        va_start(ap, fmt);
191        tty_lock(pca.tty);
192        sx_sunlock(&proctree_lock);
193        retval = kvprintf(fmt, putchar, &pca, 10, ap);
194        tty_unlock(pca.tty);
195        va_end(ap);
196        return (retval);
197}
198
199/*
200 * tprintf and vtprintf print on the controlling terminal associated with the
201 * given session, possibly to the log as well.
202 */
203void
204tprintf(struct proc *p, int pri, const char *fmt, ...)
205{
206        va_list ap;
207
208        va_start(ap, fmt);
209        vtprintf(p, pri, fmt, ap);
210        va_end(ap);
211}
212
213void
214vtprintf(struct proc *p, int pri, const char *fmt, va_list ap)
215{
216        struct tty *tp = NULL;
217        int flags = 0;
218        struct putchar_arg pca;
219        struct session *sess = NULL;
220
221        sx_slock(&proctree_lock);
222        if (pri != -1)
223                flags |= TOLOG;
224        if (p != NULL) {
225                PROC_LOCK(p);
226                if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
227                        sess = p->p_session;
228                        sess_hold(sess);
229                        PROC_UNLOCK(p);
230                        tp = sess->s_ttyp;
231                        if (tp != NULL && tty_checkoutq(tp))
232                                flags |= TOTTY;
233                        else
234                                tp = NULL;
235                } else
236                        PROC_UNLOCK(p);
237        }
238        pca.pri = pri;
239        pca.tty = tp;
240        pca.flags = flags;
241        pca.p_bufr = NULL;
242        if (pca.tty != NULL)
243                tty_lock(pca.tty);
244        sx_sunlock(&proctree_lock);
245        kvprintf(fmt, putchar, &pca, 10, ap);
246        if (pca.tty != NULL)
247                tty_unlock(pca.tty);
248        if (sess != NULL)
249                sess_release(sess);
250        msgbuftrigger = 1;
251}
252
253/*
254 * Ttyprintf displays a message on a tty; it should be used only by
255 * the tty driver, or anything that knows the underlying tty will not
256 * be revoke(2)'d away.  Other callers should use tprintf.
257 */
258int
259ttyprintf(struct tty *tp, const char *fmt, ...)
260{
261        va_list ap;
262        struct putchar_arg pca;
263        int retval;
264
265        va_start(ap, fmt);
266        pca.tty = tp;
267        pca.flags = TOTTY;
268        pca.p_bufr = NULL;
269        retval = kvprintf(fmt, putchar, &pca, 10, ap);
270        va_end(ap);
271        return (retval);
272}
273
274static int
275_vprintf(int level, int flags, const char *fmt, va_list ap)
276{
277        struct putchar_arg pca;
278        int retval;
279#ifdef PRINTF_BUFR_SIZE
280        char bufr[PRINTF_BUFR_SIZE];
281#endif
282
283        pca.tty = NULL;
284        pca.pri = level;
285        pca.flags = flags;
286#ifdef PRINTF_BUFR_SIZE
287        pca.p_bufr = bufr;
288        pca.p_next = pca.p_bufr;
289        pca.n_bufr = sizeof(bufr);
290        pca.remain = sizeof(bufr);
291        *pca.p_next = '\0';
292#else
293        /* Don't buffer console output. */
294        pca.p_bufr = NULL;
295#endif
296
297        retval = kvprintf(fmt, putchar, &pca, 10, ap);
298
299#ifdef PRINTF_BUFR_SIZE
300        /* Write any buffered console/log output: */
301        if (*pca.p_bufr != '\0') {
302                if (pca.flags & TOLOG)
303                        msglogstr(pca.p_bufr, level, /*filter_cr*/1);
304
305                if (pca.flags & TOCONS)
306                        cnputs(pca.p_bufr);
307        }
308#endif
309
310        return (retval);
311}
312#else /* __rtems__ */
313#include <rtems/bsd/bsd.h>
314#define _vprintf(level, flags, fmt, ap) rtems_bsd_vprintf(level, fmt, ap)
315#endif /* __rtems__ */
316
317/*
318 * Log writes to the log buffer, and guarantees not to sleep (so can be
319 * called by interrupt routines).  If there is no process reading the
320 * log yet, it writes to the console also.
321 */
322void
323log(int level, const char *fmt, ...)
324{
325        va_list ap;
326
327        va_start(ap, fmt);
328        vlog(level, fmt, ap);
329        va_end(ap);
330}
331
332void
333vlog(int level, const char *fmt, va_list ap)
334{
335
336        (void)_vprintf(level, log_open ? TOLOG : TOCONS | TOLOG, fmt, ap);
337#ifndef __rtems__
338        msgbuftrigger = 1;
339#endif /* __rtems__ */
340}
341
342#ifndef __rtems__
343#define CONSCHUNK 128
344
345void
346log_console(struct uio *uio)
347{
348        int c, error, nl;
349        char *consbuffer;
350        int pri;
351
352        if (!log_console_output)
353                return;
354
355        pri = LOG_INFO | LOG_CONSOLE;
356        uio = cloneuio(uio);
357        consbuffer = malloc(CONSCHUNK, M_TEMP, M_WAITOK);
358
359        nl = 0;
360        while (uio->uio_resid > 0) {
361                c = imin(uio->uio_resid, CONSCHUNK - 1);
362                error = uiomove(consbuffer, c, uio);
363                if (error != 0)
364                        break;
365                /* Make sure we're NUL-terminated */
366                consbuffer[c] = '\0';
367                if (consbuffer[c - 1] == '\n')
368                        nl = 1;
369                else
370                        nl = 0;
371                msglogstr(consbuffer, pri, /*filter_cr*/ 1);
372        }
373        /*
374         * The previous behavior in log_console() is preserved when
375         * log_console_add_linefeed is non-zero.  For that behavior, if an
376         * individual console write came in that was not terminated with a
377         * line feed, it would add a line feed.
378         *
379         * This results in different data in the message buffer than
380         * appears on the system console (which doesn't add extra line feed
381         * characters).
382         *
383         * A number of programs and rc scripts write a line feed, or a period
384         * and a line feed when they have completed their operation.  On
385         * the console, this looks seamless, but when displayed with
386         * 'dmesg -a', you wind up with output that looks like this:
387         *
388         * Updating motd:
389         * .
390         *
391         * On the console, it looks like this:
392         * Updating motd:.
393         *
394         * We could add logic to detect that situation, or just not insert
395         * the extra newlines.  Set the kern.log_console_add_linefeed
396         * sysctl/tunable variable to get the old behavior.
397         */
398        if (!nl && log_console_add_linefeed) {
399                consbuffer[0] = '\n';
400                consbuffer[1] = '\0';
401                msglogstr(consbuffer, pri, /*filter_cr*/ 1);
402        }
403        msgbuftrigger = 1;
404        free(uio, M_IOV);
405        free(consbuffer, M_TEMP);
406        return;
407}
408#endif /* __rtems__ */
409
410int
411printf(const char *fmt, ...)
412{
413        va_list ap;
414        int retval;
415
416        va_start(ap, fmt);
417        retval = vprintf(fmt, ap);
418        va_end(ap);
419
420        return (retval);
421}
422
423int
424vprintf(const char *fmt, va_list ap)
425{
426        int retval;
427
428        retval = _vprintf(-1, TOCONS | TOLOG, fmt, ap);
429
430#ifndef __rtems__
431        if (!panicstr)
432                msgbuftrigger = 1;
433#endif /* __rtems__ */
434
435        return (retval);
436}
437
438#ifndef __rtems__
439static void
440putbuf(int c, struct putchar_arg *ap)
441{
442        /* Check if no console output buffer was provided. */
443        if (ap->p_bufr == NULL) {
444                /* Output direct to the console. */
445                if (ap->flags & TOCONS)
446                        cnputc(c);
447
448                if (ap->flags & TOLOG)
449                        msglogchar(c, ap->pri);
450        } else {
451                /* Buffer the character: */
452                *ap->p_next++ = c;
453                ap->remain--;
454
455                /* Always leave the buffer zero terminated. */
456                *ap->p_next = '\0';
457
458                /* Check if the buffer needs to be flushed. */
459                if (ap->remain == 2 || c == '\n') {
460
461                        if (ap->flags & TOLOG)
462                                msglogstr(ap->p_bufr, ap->pri, /*filter_cr*/1);
463
464                        if (ap->flags & TOCONS) {
465                                if ((panicstr == NULL) && (constty != NULL))
466                                        msgbuf_addstr(&consmsgbuf, -1,
467                                            ap->p_bufr, /*filter_cr*/ 0);
468
469                                if ((constty == NULL) ||(always_console_output))
470                                        cnputs(ap->p_bufr);
471                        }
472
473                        ap->p_next = ap->p_bufr;
474                        ap->remain = ap->n_bufr;
475                        *ap->p_next = '\0';
476                }
477
478                /*
479                 * Since we fill the buffer up one character at a time,
480                 * this should not happen.  We should always catch it when
481                 * ap->remain == 2 (if not sooner due to a newline), flush
482                 * the buffer and move on.  One way this could happen is
483                 * if someone sets PRINTF_BUFR_SIZE to 1 or something
484                 * similarly silly.
485                 */
486                KASSERT(ap->remain > 2, ("Bad buffer logic, remain = %zd",
487                    ap->remain));
488        }
489}
490
491/*
492 * Print a character on console or users terminal.  If destination is
493 * the console then the last bunch of characters are saved in msgbuf for
494 * inspection later.
495 */
496static void
497putchar(int c, void *arg)
498{
499        struct putchar_arg *ap = (struct putchar_arg*) arg;
500        struct tty *tp = ap->tty;
501        int flags = ap->flags;
502
503        /* Don't use the tty code after a panic or while in ddb. */
504        if (kdb_active) {
505                if (c != '\0')
506                        cnputc(c);
507                return;
508        }
509
510        if ((flags & TOTTY) && tp != NULL && panicstr == NULL)
511                tty_putchar(tp, c);
512
513        if ((flags & (TOCONS | TOLOG)) && c != '\0')
514                putbuf(c, ap);
515}
516#endif /* __rtems__ */
517
518/*
519 * Scaled down version of sprintf(3).
520 */
521int
522sprintf(char *buf, const char *cfmt, ...)
523{
524        int retval;
525        va_list ap;
526
527        va_start(ap, cfmt);
528        retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
529        buf[retval] = '\0';
530        va_end(ap);
531        return (retval);
532}
533
534/*
535 * Scaled down version of vsprintf(3).
536 */
537int
538vsprintf(char *buf, const char *cfmt, va_list ap)
539{
540        int retval;
541
542        retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
543        buf[retval] = '\0';
544        return (retval);
545}
546
547/*
548 * Scaled down version of snprintf(3).
549 */
550int
551snprintf(char *str, size_t size, const char *format, ...)
552{
553        int retval;
554        va_list ap;
555
556        va_start(ap, format);
557        retval = vsnprintf(str, size, format, ap);
558        va_end(ap);
559        return(retval);
560}
561
562/*
563 * Scaled down version of vsnprintf(3).
564 */
565int
566vsnprintf(char *str, size_t size, const char *format, va_list ap)
567{
568        struct snprintf_arg info;
569        int retval;
570
571        info.str = str;
572        info.remain = size;
573        retval = kvprintf(format, snprintf_func, &info, 10, ap);
574        if (info.remain >= 1)
575                *info.str++ = '\0';
576        return (retval);
577}
578
579/*
580 * Kernel version which takes radix argument vsnprintf(3).
581 */
582int
583vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
584{
585        struct snprintf_arg info;
586        int retval;
587
588        info.str = str;
589        info.remain = size;
590        retval = kvprintf(format, snprintf_func, &info, radix, ap);
591        if (info.remain >= 1)
592                *info.str++ = '\0';
593        return (retval);
594}
595
596static void
597snprintf_func(int ch, void *arg)
598{
599        struct snprintf_arg *const info = arg;
600
601        if (info->remain >= 2) {
602                *info->str++ = ch;
603                info->remain--;
604        }
605}
606
607/*
608 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
609 * order; return an optional length and a pointer to the last character
610 * written in the buffer (i.e., the first character of the string).
611 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
612 */
613static char *
614ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
615{
616        char *p, c;
617
618        p = nbuf;
619        *p = '\0';
620        do {
621                c = hex2ascii(num % base);
622                *++p = upper ? toupper(c) : c;
623        } while (num /= base);
624        if (lenp)
625                *lenp = p - nbuf;
626        return (p);
627}
628
629/*
630 * Scaled down version of printf(3).
631 *
632 * Two additional formats:
633 *
634 * The format %b is supported to decode error registers.
635 * Its usage is:
636 *
637 *      printf("reg=%b\n", regval, "<base><arg>*");
638 *
639 * where <base> is the output base expressed as a control character, e.g.
640 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
641 * the first of which gives the bit number to be inspected (origin 1), and
642 * the next characters (up to a control character, i.e. a character <= 32),
643 * give the name of the register.  Thus:
644 *
645 *      kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
646 *
647 * would produce output:
648 *
649 *      reg=3<BITTWO,BITONE>
650 *
651 * XXX:  %D  -- Hexdump, takes pointer and separator string:
652 *              ("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
653 *              ("%*D", len, ptr, " " -> XX XX XX XX ...
654 */
655int
656kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
657{
658#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
659        char nbuf[MAXNBUF];
660        char *d;
661        const char *p, *percent, *q;
662        u_char *up;
663        int ch, n;
664        uintmax_t num;
665        int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
666        int cflag, hflag, jflag, tflag, zflag;
667        int dwidth, upper;
668        char padc;
669        int stop = 0, retval = 0;
670
671        num = 0;
672        if (!func)
673                d = (char *) arg;
674        else
675                d = NULL;
676
677        if (fmt == NULL)
678                fmt = "(fmt null)\n";
679
680        if (radix < 2 || radix > 36)
681                radix = 10;
682
683        for (;;) {
684                padc = ' ';
685                width = 0;
686                while ((ch = (u_char)*fmt++) != '%' || stop) {
687                        if (ch == '\0')
688                                return (retval);
689                        PCHAR(ch);
690                }
691                percent = fmt - 1;
692                qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
693                sign = 0; dot = 0; dwidth = 0; upper = 0;
694                cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
695reswitch:       switch (ch = (u_char)*fmt++) {
696                case '.':
697                        dot = 1;
698                        goto reswitch;
699                case '#':
700                        sharpflag = 1;
701                        goto reswitch;
702                case '+':
703                        sign = 1;
704                        goto reswitch;
705                case '-':
706                        ladjust = 1;
707                        goto reswitch;
708                case '%':
709                        PCHAR(ch);
710                        break;
711                case '*':
712                        if (!dot) {
713                                width = va_arg(ap, int);
714                                if (width < 0) {
715                                        ladjust = !ladjust;
716                                        width = -width;
717                                }
718                        } else {
719                                dwidth = va_arg(ap, int);
720                        }
721                        goto reswitch;
722                case '0':
723                        if (!dot) {
724                                padc = '0';
725                                goto reswitch;
726                        }
727                case '1': case '2': case '3': case '4':
728                case '5': case '6': case '7': case '8': case '9':
729                                for (n = 0;; ++fmt) {
730                                        n = n * 10 + ch - '0';
731                                        ch = *fmt;
732                                        if (ch < '0' || ch > '9')
733                                                break;
734                                }
735                        if (dot)
736                                dwidth = n;
737                        else
738                                width = n;
739                        goto reswitch;
740                case 'b':
741                        num = (u_int)va_arg(ap, int);
742                        p = va_arg(ap, char *);
743                        for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
744                                PCHAR(*q--);
745
746                        if (num == 0)
747                                break;
748
749                        for (tmp = 0; *p;) {
750                                n = *p++;
751                                if (num & (1 << (n - 1))) {
752                                        PCHAR(tmp ? ',' : '<');
753                                        for (; (n = *p) > ' '; ++p)
754                                                PCHAR(n);
755                                        tmp = 1;
756                                } else
757                                        for (; *p > ' '; ++p)
758                                                continue;
759                        }
760                        if (tmp)
761                                PCHAR('>');
762                        break;
763                case 'c':
764                        width -= 1;
765
766                        if (!ladjust && width > 0)
767                                while (width--)
768                                        PCHAR(padc);
769                        PCHAR(va_arg(ap, int));
770                        if (ladjust && width > 0)
771                                while (width--)
772                                        PCHAR(padc);
773                        break;
774                case 'D':
775                        up = va_arg(ap, u_char *);
776                        p = va_arg(ap, char *);
777                        if (!width)
778                                width = 16;
779                        while(width--) {
780                                PCHAR(hex2ascii(*up >> 4));
781                                PCHAR(hex2ascii(*up & 0x0f));
782                                up++;
783                                if (width)
784                                        for (q=p;*q;q++)
785                                                PCHAR(*q);
786                        }
787                        break;
788                case 'd':
789                case 'i':
790                        base = 10;
791                        sign = 1;
792                        goto handle_sign;
793                case 'h':
794                        if (hflag) {
795                                hflag = 0;
796                                cflag = 1;
797                        } else
798                                hflag = 1;
799                        goto reswitch;
800                case 'j':
801                        jflag = 1;
802                        goto reswitch;
803                case 'l':
804                        if (lflag) {
805                                lflag = 0;
806                                qflag = 1;
807                        } else
808                                lflag = 1;
809                        goto reswitch;
810                case 'n':
811                        if (jflag)
812                                *(va_arg(ap, intmax_t *)) = retval;
813                        else if (qflag)
814                                *(va_arg(ap, quad_t *)) = retval;
815                        else if (lflag)
816                                *(va_arg(ap, long *)) = retval;
817                        else if (zflag)
818                                *(va_arg(ap, size_t *)) = retval;
819                        else if (hflag)
820                                *(va_arg(ap, short *)) = retval;
821                        else if (cflag)
822                                *(va_arg(ap, char *)) = retval;
823                        else
824                                *(va_arg(ap, int *)) = retval;
825                        break;
826#ifdef __rtems__
827                case 'm':
828                        p = strerror(errno);
829                        goto handle_string;
830#endif /* __rtems__ */
831                case 'o':
832                        base = 8;
833                        goto handle_nosign;
834                case 'p':
835                        base = 16;
836                        sharpflag = (width == 0);
837                        sign = 0;
838                        num = (uintptr_t)va_arg(ap, void *);
839                        goto number;
840                case 'q':
841                        qflag = 1;
842                        goto reswitch;
843                case 'r':
844                        base = radix;
845                        if (sign)
846                                goto handle_sign;
847                        goto handle_nosign;
848                case 's':
849                        p = va_arg(ap, char *);
850#ifdef __rtems__
851handle_string:
852#endif /* __rtems__ */
853                        if (p == NULL)
854                                p = "(null)";
855                        if (!dot)
856                                n = strlen (p);
857                        else
858                                for (n = 0; n < dwidth && p[n]; n++)
859                                        continue;
860
861                        width -= n;
862
863                        if (!ladjust && width > 0)
864                                while (width--)
865                                        PCHAR(padc);
866                        while (n--)
867                                PCHAR(*p++);
868                        if (ladjust && width > 0)
869                                while (width--)
870                                        PCHAR(padc);
871                        break;
872                case 't':
873                        tflag = 1;
874                        goto reswitch;
875                case 'u':
876                        base = 10;
877                        goto handle_nosign;
878                case 'X':
879                        upper = 1;
880                case 'x':
881                        base = 16;
882                        goto handle_nosign;
883                case 'y':
884                        base = 16;
885                        sign = 1;
886                        goto handle_sign;
887                case 'z':
888                        zflag = 1;
889                        goto reswitch;
890handle_nosign:
891                        sign = 0;
892                        if (jflag)
893                                num = va_arg(ap, uintmax_t);
894                        else if (qflag)
895                                num = va_arg(ap, u_quad_t);
896                        else if (tflag)
897                                num = va_arg(ap, ptrdiff_t);
898                        else if (lflag)
899                                num = va_arg(ap, u_long);
900                        else if (zflag)
901                                num = va_arg(ap, size_t);
902                        else if (hflag)
903                                num = (u_short)va_arg(ap, int);
904                        else if (cflag)
905                                num = (u_char)va_arg(ap, int);
906                        else
907                                num = va_arg(ap, u_int);
908                        goto number;
909handle_sign:
910                        if (jflag)
911                                num = va_arg(ap, intmax_t);
912                        else if (qflag)
913                                num = va_arg(ap, quad_t);
914                        else if (tflag)
915                                num = va_arg(ap, ptrdiff_t);
916                        else if (lflag)
917                                num = va_arg(ap, long);
918                        else if (zflag)
919                                num = va_arg(ap, ssize_t);
920                        else if (hflag)
921                                num = (short)va_arg(ap, int);
922                        else if (cflag)
923                                num = (char)va_arg(ap, int);
924                        else
925                                num = va_arg(ap, int);
926number:
927                        if (sign && (intmax_t)num < 0) {
928                                neg = 1;
929                                num = -(intmax_t)num;
930                        }
931                        p = ksprintn(nbuf, num, base, &n, upper);
932                        tmp = 0;
933                        if (sharpflag && num != 0) {
934                                if (base == 8)
935                                        tmp++;
936                                else if (base == 16)
937                                        tmp += 2;
938                        }
939                        if (neg)
940                                tmp++;
941
942                        if (!ladjust && padc == '0')
943                                dwidth = width - tmp;
944                        width -= tmp + imax(dwidth, n);
945                        dwidth -= n;
946                        if (!ladjust)
947                                while (width-- > 0)
948                                        PCHAR(' ');
949                        if (neg)
950                                PCHAR('-');
951                        if (sharpflag && num != 0) {
952                                if (base == 8) {
953                                        PCHAR('0');
954                                } else if (base == 16) {
955                                        PCHAR('0');
956                                        PCHAR('x');
957                                }
958                        }
959                        while (dwidth-- > 0)
960                                PCHAR('0');
961
962                        while (*p)
963                                PCHAR(*p--);
964
965                        if (ladjust)
966                                while (width-- > 0)
967                                        PCHAR(' ');
968
969                        break;
970                default:
971                        while (percent < fmt)
972                                PCHAR(*percent++);
973                        /*
974                         * Since we ignore a formatting argument it is no
975                         * longer safe to obey the remaining formatting
976                         * arguments as the arguments will no longer match
977                         * the format specs.
978                         */
979                        stop = 1;
980                        break;
981                }
982        }
983#undef PCHAR
984}
985
986#ifndef __rtems__
987/*
988 * Put character in log buffer with a particular priority.
989 */
990static void
991msglogchar(int c, int pri)
992{
993        static int lastpri = -1;
994        static int dangling;
995        char nbuf[MAXNBUF];
996        char *p;
997
998        if (!msgbufmapped)
999                return;
1000        if (c == '\0' || c == '\r')
1001                return;
1002        if (pri != -1 && pri != lastpri) {
1003                if (dangling) {
1004                        msgbuf_addchar(msgbufp, '\n');
1005                        dangling = 0;
1006                }
1007                msgbuf_addchar(msgbufp, '<');
1008                for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL, 0); *p;)
1009                        msgbuf_addchar(msgbufp, *p--);
1010                msgbuf_addchar(msgbufp, '>');
1011                lastpri = pri;
1012        }
1013        msgbuf_addchar(msgbufp, c);
1014        if (c == '\n') {
1015                dangling = 0;
1016                lastpri = -1;
1017        } else {
1018                dangling = 1;
1019        }
1020}
1021
1022static void
1023msglogstr(char *str, int pri, int filter_cr)
1024{
1025        if (!msgbufmapped)
1026                return;
1027
1028        msgbuf_addstr(msgbufp, pri, str, filter_cr);
1029}
1030
1031void
1032msgbufinit(void *ptr, int size)
1033{
1034        char *cp;
1035        static struct msgbuf *oldp = NULL;
1036
1037        size -= sizeof(*msgbufp);
1038        cp = (char *)ptr;
1039        msgbufp = (struct msgbuf *)(cp + size);
1040        msgbuf_reinit(msgbufp, cp, size);
1041        if (msgbufmapped && oldp != msgbufp)
1042                msgbuf_copy(oldp, msgbufp);
1043        msgbufmapped = 1;
1044        oldp = msgbufp;
1045}
1046
1047static int unprivileged_read_msgbuf = 1;
1048SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
1049    CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
1050    "Unprivileged processes may read the kernel message buffer");
1051
1052/* Sysctls for accessing/clearing the msgbuf */
1053static int
1054sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
1055{
1056        char buf[128];
1057        u_int seq;
1058        int error, len;
1059
1060        if (!unprivileged_read_msgbuf) {
1061                error = priv_check(req->td, PRIV_MSGBUF);
1062                if (error)
1063                        return (error);
1064        }
1065
1066        /* Read the whole buffer, one chunk at a time. */
1067        mtx_lock(&msgbuf_lock);
1068        msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
1069        for (;;) {
1070                len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq);
1071                mtx_unlock(&msgbuf_lock);
1072                if (len == 0)
1073                        return (SYSCTL_OUT(req, "", 1)); /* add nulterm */
1074
1075                error = sysctl_handle_opaque(oidp, buf, len, req);
1076                if (error)
1077                        return (error);
1078
1079                mtx_lock(&msgbuf_lock);
1080        }
1081}
1082
1083SYSCTL_PROC(_kern, OID_AUTO, msgbuf,
1084    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
1085    NULL, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
1086
1087static int msgbuf_clearflag;
1088
1089static int
1090sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
1091{
1092        int error;
1093        error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
1094        if (!error && req->newptr) {
1095                mtx_lock(&msgbuf_lock);
1096                msgbuf_clear(msgbufp);
1097                mtx_unlock(&msgbuf_lock);
1098                msgbuf_clearflag = 0;
1099        }
1100        return (error);
1101}
1102
1103SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
1104    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_MPSAFE,
1105    &msgbuf_clearflag, 0, sysctl_kern_msgbuf_clear, "I",
1106    "Clear kernel message buffer");
1107
1108#ifdef DDB
1109
1110DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
1111{
1112        int i, j;
1113
1114        if (!msgbufmapped) {
1115                db_printf("msgbuf not mapped yet\n");
1116                return;
1117        }
1118        db_printf("msgbufp = %p\n", msgbufp);
1119        db_printf("magic = %x, size = %d, r= %u, w = %u, ptr = %p, cksum= %u\n",
1120            msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_rseq,
1121            msgbufp->msg_wseq, msgbufp->msg_ptr, msgbufp->msg_cksum);
1122        for (i = 0; i < msgbufp->msg_size && !db_pager_quit; i++) {
1123                j = MSGBUF_SEQ_TO_POS(msgbufp, i + msgbufp->msg_rseq);
1124                db_printf("%c", msgbufp->msg_ptr[j]);
1125        }
1126        db_printf("\n");
1127}
1128
1129#endif /* DDB */
1130
1131void
1132hexdump(const void *ptr, int length, const char *hdr, int flags)
1133{
1134        int i, j, k;
1135        int cols;
1136        const unsigned char *cp;
1137        char delim;
1138
1139        if ((flags & HD_DELIM_MASK) != 0)
1140                delim = (flags & HD_DELIM_MASK) >> 8;
1141        else
1142                delim = ' ';
1143
1144        if ((flags & HD_COLUMN_MASK) != 0)
1145                cols = flags & HD_COLUMN_MASK;
1146        else
1147                cols = 16;
1148
1149        cp = ptr;
1150        for (i = 0; i < length; i+= cols) {
1151                if (hdr != NULL)
1152                        printf("%s", hdr);
1153
1154                if ((flags & HD_OMIT_COUNT) == 0)
1155                        printf("%04x  ", i);
1156
1157                if ((flags & HD_OMIT_HEX) == 0) {
1158                        for (j = 0; j < cols; j++) {
1159                                k = i + j;
1160                                if (k < length)
1161                                        printf("%c%02x", delim, cp[k]);
1162                                else
1163                                        printf("   ");
1164                        }
1165                }
1166
1167                if ((flags & HD_OMIT_CHARS) == 0) {
1168                        printf("  |");
1169                        for (j = 0; j < cols; j++) {
1170                                k = i + j;
1171                                if (k >= length)
1172                                        printf(" ");
1173                                else if (cp[k] >= ' ' && cp[k] <= '~')
1174                                        printf("%c", cp[k]);
1175                                else
1176                                        printf(".");
1177                        }
1178                        printf("|");
1179                }
1180                printf("\n");
1181        }
1182}
1183#endif /* __rtems__ */
1184#endif /* _KERNEL */
1185
1186void
1187sbuf_hexdump(struct sbuf *sb, const void *ptr, int length, const char *hdr,
1188             int flags)
1189{
1190        int i, j, k;
1191        int cols;
1192        const unsigned char *cp;
1193        char delim;
1194
1195        if ((flags & HD_DELIM_MASK) != 0)
1196                delim = (flags & HD_DELIM_MASK) >> 8;
1197        else
1198                delim = ' ';
1199
1200        if ((flags & HD_COLUMN_MASK) != 0)
1201                cols = flags & HD_COLUMN_MASK;
1202        else
1203                cols = 16;
1204
1205        cp = ptr;
1206        for (i = 0; i < length; i+= cols) {
1207                if (hdr != NULL)
1208                        sbuf_printf(sb, "%s", hdr);
1209
1210                if ((flags & HD_OMIT_COUNT) == 0)
1211                        sbuf_printf(sb, "%04x  ", i);
1212
1213                if ((flags & HD_OMIT_HEX) == 0) {
1214                        for (j = 0; j < cols; j++) {
1215                                k = i + j;
1216                                if (k < length)
1217                                        sbuf_printf(sb, "%c%02x", delim, cp[k]);
1218                                else
1219                                        sbuf_printf(sb, "   ");
1220                        }
1221                }
1222
1223                if ((flags & HD_OMIT_CHARS) == 0) {
1224                        sbuf_printf(sb, "  |");
1225                        for (j = 0; j < cols; j++) {
1226                                k = i + j;
1227                                if (k >= length)
1228                                        sbuf_printf(sb, " ");
1229                                else if (cp[k] >= ' ' && cp[k] <= '~')
1230                                        sbuf_printf(sb, "%c", cp[k]);
1231                                else
1232                                        sbuf_printf(sb, ".");
1233                        }
1234                        sbuf_printf(sb, "|");
1235                }
1236                sbuf_printf(sb, "\n");
1237        }
1238}
1239
1240#ifndef __rtems__
1241#ifdef _KERNEL
1242void
1243counted_warning(unsigned *counter, const char *msg)
1244{
1245        struct thread *td;
1246        unsigned c;
1247
1248        for (;;) {
1249                c = *counter;
1250                if (c == 0)
1251                        break;
1252                if (atomic_cmpset_int(counter, c, c - 1)) {
1253                        td = curthread;
1254                        log(LOG_INFO, "pid %d (%s) %s%s\n",
1255                            td->td_proc->p_pid, td->td_name, msg,
1256                            c > 1 ? "" : " - not logging anymore");
1257                        break;
1258                }
1259        }
1260}
1261#endif
1262#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.