11541Srgrimes/*- 21541Srgrimes * Copyright (c) 1986, 1988, 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * (c) UNIX System Laboratories, Inc. 51541Srgrimes * All or some portions of this file are derived from material licensed 61541Srgrimes * to the University of California by American Telephone and Telegraph 71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 81541Srgrimes * the permission of UNIX System Laboratories, Inc. 91541Srgrimes * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 111541Srgrimes * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 1. Redistributions of source code must retain the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer. 151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer in the 171541Srgrimes * documentation and/or other materials provided with the distribution. 181541Srgrimes * 4. Neither the name of the University nor the names of its contributors 191541Srgrimes * may be used to endorse or promote products derived from this software 201541Srgrimes * without specific prior written permission. 211541Srgrimes * 221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321541Srgrimes * SUCH DAMAGE. 331541Srgrimes * 341541Srgrimes * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 351541Srgrimes */ 361541Srgrimes 37116182Sobrien#include <sys/cdefs.h> 38116182Sobrien__FBSDID("$FreeBSD: stable/10/sys/kern/subr_prf.c 321108 2017-07-18 06:45:41Z ngie $"); 39116182Sobrien 40284435Sken#ifdef _KERNEL 41108678Sphk#include "opt_ddb.h" 42164760Sjb#include "opt_printf.h" 43284435Sken#endif /* _KERNEL */ 44108678Sphk 451541Srgrimes#include <sys/param.h> 46284435Sken#ifdef _KERNEL 471541Srgrimes#include <sys/systm.h> 4891140Stanimura#include <sys/lock.h> 49131931Smarcel#include <sys/kdb.h> 5091140Stanimura#include <sys/mutex.h> 5191140Stanimura#include <sys/sx.h> 5236441Sphk#include <sys/kernel.h> 531541Srgrimes#include <sys/msgbuf.h> 5430354Sphk#include <sys/malloc.h> 55164033Srwatson#include <sys/priv.h> 561541Srgrimes#include <sys/proc.h> 57106855Smux#include <sys/stddef.h> 5890490Sphk#include <sys/sysctl.h> 591541Srgrimes#include <sys/tty.h> 601541Srgrimes#include <sys/syslog.h> 6149558Sphk#include <sys/cons.h> 6270239Sphk#include <sys/uio.h> 63284435Sken#endif 64156518Sjkim#include <sys/ctype.h> 65284435Sken#include <sys/sbuf.h> 661541Srgrimes 67108678Sphk#ifdef DDB 68108678Sphk#include <ddb/ddb.h> 69108678Sphk#endif 70108678Sphk 711541Srgrimes/* 721541Srgrimes * Note that stdarg.h and the ANSI style va_start macro is used for both 731541Srgrimes * ANSI and traditional C compilers. 741541Srgrimes */ 75321108Sngie#ifdef _KERNEL 761541Srgrimes#include <machine/stdarg.h> 77321108Sngie#else 78321108Sngie#include <stdarg.h> 79321108Sngie#endif 801541Srgrimes 81321108Sngie/* 82321108Sngie * This is needed for sbuf_putbuf() when compiled into userland. Due to the 83321108Sngie * shared nature of this file, it's the only place to put it. 84321108Sngie */ 85321108Sngie#ifndef _KERNEL 86321108Sngie#include <stdio.h> 87321108Sngie#endif 88321108Sngie 89284435Sken#ifdef _KERNEL 90284435Sken 911541Srgrimes#define TOCONS 0x01 921541Srgrimes#define TOTTY 0x02 931541Srgrimes#define TOLOG 0x04 941541Srgrimes 9548728Speter/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */ 9697749Sdes#define MAXNBUF (sizeof(intmax_t) * NBBY + 1) 9747773Sarchie 9841479Sarchiestruct putchar_arg { 9947822Sarchie int flags; 10070239Sphk int pri; 10147822Sarchie struct tty *tty; 102163858Sjb char *p_bufr; 103163858Sjb size_t n_bufr; 104163858Sjb char *p_next; 105163858Sjb size_t remain; 10641479Sarchie}; 10741479Sarchie 10841479Sarchiestruct snprintf_arg { 10947822Sarchie char *str; 11047822Sarchie size_t remain; 11141479Sarchie}; 11241479Sarchie 11370239Sphkextern int log_open; 11470239Sphk 11570239Sphkstatic void msglogchar(int c, int pri); 116222537Skenstatic void msglogstr(char *str, int pri, int filter_cr); 11792723Salfredstatic void putchar(int ch, void *arg); 118156518Sjkimstatic char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper); 11992723Salfredstatic void snprintf_func(int ch, void *arg); 1201541Srgrimes 12136441Sphkstatic int msgbufmapped; /* Set when safe to use msgbuf */ 12270239Sphkint msgbuftrigger; 1231541Srgrimes 12495713Sdwmalonestatic int log_console_output = 1; 125101693SdwmaloneTUNABLE_INT("kern.log_console_output", &log_console_output); 12695713SdwmaloneSYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RW, 127130700Sgreen &log_console_output, 0, "Duplicate console output to the syslog."); 12895713Sdwmalone 129222537Sken/* 130222537Sken * See the comment in log_console() below for more explanation of this. 131222537Sken */ 132222537Skenstatic int log_console_add_linefeed = 0; 133222537SkenTUNABLE_INT("kern.log_console_add_linefeed", &log_console_add_linefeed); 134222537SkenSYSCTL_INT(_kern, OID_AUTO, log_console_add_linefeed, CTLFLAG_RW, 135222537Sken &log_console_add_linefeed, 0, "log_console() adds extra newlines."); 136222537Sken 137130700Sgreenstatic int always_console_output = 0; 138130700SgreenTUNABLE_INT("kern.always_console_output", &always_console_output); 139130700SgreenSYSCTL_INT(_kern, OID_AUTO, always_console_output, CTLFLAG_RW, 140130700Sgreen &always_console_output, 0, "Always output to console despite TIOCCONS."); 141130700Sgreen 1421541Srgrimes/* 1431541Srgrimes * Warn that a system table is full. 1441541Srgrimes */ 1451541Srgrimesvoid 14670239Sphktablefull(const char *tab) 1471541Srgrimes{ 1481541Srgrimes 1491541Srgrimes log(LOG_ERR, "%s: table is full\n", tab); 1501541Srgrimes} 1511541Srgrimes 1521541Srgrimes/* 1531541Srgrimes * Uprintf prints to the controlling terminal for the current process. 1541541Srgrimes */ 15549047Sdfrint 1561541Srgrimesuprintf(const char *fmt, ...) 1571541Srgrimes{ 1581541Srgrimes va_list ap; 15913446Sphk struct putchar_arg pca; 160189102Sed struct proc *p; 161189102Sed struct thread *td; 16291140Stanimura int retval; 1631541Srgrimes 164189102Sed td = curthread; 165189102Sed if (TD_IS_IDLETHREAD(td)) 16691140Stanimura return (0); 16791140Stanimura 168181905Sed sx_slock(&proctree_lock); 169189102Sed p = td->td_proc; 17091140Stanimura PROC_LOCK(p); 17191140Stanimura if ((p->p_flag & P_CONTROLT) == 0) { 17291140Stanimura PROC_UNLOCK(p); 173255509Skib sx_sunlock(&proctree_lock); 174255509Skib return (0); 1751541Srgrimes } 17691140Stanimura SESS_LOCK(p->p_session); 17791140Stanimura pca.tty = p->p_session->s_ttyp; 17891140Stanimura SESS_UNLOCK(p->p_session); 17991140Stanimura PROC_UNLOCK(p); 180150560Srwatson if (pca.tty == NULL) { 181255509Skib sx_sunlock(&proctree_lock); 182255509Skib return (0); 183150560Srwatson } 18491140Stanimura pca.flags = TOTTY; 185222804Sken pca.p_bufr = NULL; 18691140Stanimura va_start(ap, fmt); 187181905Sed tty_lock(pca.tty); 188255509Skib sx_sunlock(&proctree_lock); 18991140Stanimura retval = kvprintf(fmt, putchar, &pca, 10, ap); 190181905Sed tty_unlock(pca.tty); 19191140Stanimura va_end(ap); 19290490Sphk return (retval); 1931541Srgrimes} 1941541Srgrimes 1951541Srgrimes/* 196255351Snp * tprintf and vtprintf print on the controlling terminal associated with the 197255351Snp * given session, possibly to the log as well. 1981541Srgrimes */ 19969214Sphkvoid 20069214Sphktprintf(struct proc *p, int pri, const char *fmt, ...) 2011541Srgrimes{ 202255351Snp va_list ap; 203255351Snp 204255351Snp va_start(ap, fmt); 205255351Snp vtprintf(p, pri, fmt, ap); 206255351Snp va_end(ap); 207255351Snp} 208255351Snp 209255351Snpvoid 210255351Snpvtprintf(struct proc *p, int pri, const char *fmt, va_list ap) 211255351Snp{ 2121541Srgrimes struct tty *tp = NULL; 213113634Sjhb int flags = 0; 21413446Sphk struct putchar_arg pca; 215113634Sjhb struct session *sess = NULL; 2161541Srgrimes 217181905Sed sx_slock(&proctree_lock); 21870239Sphk if (pri != -1) 21969214Sphk flags |= TOLOG; 22091140Stanimura if (p != NULL) { 22191140Stanimura PROC_LOCK(p); 22291140Stanimura if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 223113634Sjhb sess = p->p_session; 224181905Sed sess_hold(sess); 22591140Stanimura PROC_UNLOCK(p); 226113634Sjhb tp = sess->s_ttyp; 227181905Sed if (tp != NULL && tty_checkoutq(tp)) 22891140Stanimura flags |= TOTTY; 22991140Stanimura else 23091140Stanimura tp = NULL; 23191140Stanimura } else 23291140Stanimura PROC_UNLOCK(p); 23369214Sphk } 23470239Sphk pca.pri = pri; 23513446Sphk pca.tty = tp; 23613446Sphk pca.flags = flags; 237222804Sken pca.p_bufr = NULL; 238181905Sed if (pca.tty != NULL) 239181905Sed tty_lock(pca.tty); 240255509Skib sx_sunlock(&proctree_lock); 241115538Sphk kvprintf(fmt, putchar, &pca, 10, ap); 242181905Sed if (pca.tty != NULL) 243181905Sed tty_unlock(pca.tty); 244143740Sphk if (sess != NULL) 245181905Sed sess_release(sess); 24670239Sphk msgbuftrigger = 1; 2471541Srgrimes} 2481541Srgrimes 2491541Srgrimes/* 2501541Srgrimes * Ttyprintf displays a message on a tty; it should be used only by 2511541Srgrimes * the tty driver, or anything that knows the underlying tty will not 2521541Srgrimes * be revoke(2)'d away. Other callers should use tprintf. 2531541Srgrimes */ 25449047Sdfrint 2551541Srgrimesttyprintf(struct tty *tp, const char *fmt, ...) 2561541Srgrimes{ 2571541Srgrimes va_list ap; 25813446Sphk struct putchar_arg pca; 25949047Sdfr int retval; 26049047Sdfr 2611541Srgrimes va_start(ap, fmt); 26213446Sphk pca.tty = tp; 26313446Sphk pca.flags = TOTTY; 264222804Sken pca.p_bufr = NULL; 26549047Sdfr retval = kvprintf(fmt, putchar, &pca, 10, ap); 2661541Srgrimes va_end(ap); 26790490Sphk return (retval); 2681541Srgrimes} 2691541Srgrimes 270263941Sbdrewerystatic int 271263941Sbdrewery_vprintf(int level, int flags, const char *fmt, va_list ap) 2721541Srgrimes{ 27370239Sphk struct putchar_arg pca; 274263941Sbdrewery int retval; 275222537Sken#ifdef PRINTF_BUFR_SIZE 276222537Sken char bufr[PRINTF_BUFR_SIZE]; 277222537Sken#endif 2781541Srgrimes 27970239Sphk pca.tty = NULL; 28070239Sphk pca.pri = level; 281263941Sbdrewery pca.flags = flags; 282222537Sken#ifdef PRINTF_BUFR_SIZE 283222537Sken pca.p_bufr = bufr; 284222537Sken pca.p_next = pca.p_bufr; 285222537Sken pca.n_bufr = sizeof(bufr); 286222537Sken pca.remain = sizeof(bufr); 287222537Sken *pca.p_next = '\0'; 288222537Sken#else 289263941Sbdrewery /* Don't buffer console output. */ 290163858Sjb pca.p_bufr = NULL; 291222537Sken#endif 29270239Sphk 293263941Sbdrewery retval = kvprintf(fmt, putchar, &pca, 10, ap); 29413446Sphk 295222537Sken#ifdef PRINTF_BUFR_SIZE 296222537Sken /* Write any buffered console/log output: */ 297222537Sken if (*pca.p_bufr != '\0') { 298222537Sken if (pca.flags & TOLOG) 299222537Sken msglogstr(pca.p_bufr, level, /*filter_cr*/1); 300222537Sken 301222537Sken if (pca.flags & TOCONS) 302222537Sken cnputs(pca.p_bufr); 303222537Sken } 304222537Sken#endif 305263941Sbdrewery 306263941Sbdrewery return (retval); 307263941Sbdrewery} 308263941Sbdrewery 309263941Sbdrewery/* 310263941Sbdrewery * Log writes to the log buffer, and guarantees not to sleep (so can be 311263941Sbdrewery * called by interrupt routines). If there is no process reading the 312263941Sbdrewery * log yet, it writes to the console also. 313263941Sbdrewery */ 314263941Sbdreweryvoid 315263941Sbdrewerylog(int level, const char *fmt, ...) 316263941Sbdrewery{ 317263941Sbdrewery va_list ap; 318263941Sbdrewery 319263941Sbdrewery va_start(ap, fmt); 320288497Svangyzen (void)_vprintf(level, log_open ? TOLOG : TOCONS | TOLOG, fmt, ap); 321263941Sbdrewery va_end(ap); 322263941Sbdrewery 32370240Sphk msgbuftrigger = 1; 3241541Srgrimes} 3251541Srgrimes 32670239Sphk#define CONSCHUNK 128 32770239Sphk 32870239Sphkvoid 32970239Sphklog_console(struct uio *uio) 3301541Srgrimes{ 331222537Sken int c, error, nl; 33270239Sphk char *consbuffer; 33370239Sphk int pri; 3341541Srgrimes 33595713Sdwmalone if (!log_console_output) 33695713Sdwmalone return; 33795713Sdwmalone 33870239Sphk pri = LOG_INFO | LOG_CONSOLE; 339131897Sphk uio = cloneuio(uio); 340131897Sphk consbuffer = malloc(CONSCHUNK, M_TEMP, M_WAITOK); 34170239Sphk 342186383Sed nl = 0; 34370239Sphk while (uio->uio_resid > 0) { 344222537Sken c = imin(uio->uio_resid, CONSCHUNK - 1); 34570239Sphk error = uiomove(consbuffer, c, uio); 34670239Sphk if (error != 0) 347104114Sphk break; 348222537Sken /* Make sure we're NUL-terminated */ 349222537Sken consbuffer[c] = '\0'; 350222537Sken if (consbuffer[c - 1] == '\n') 351222537Sken nl = 1; 352222537Sken else 353222537Sken nl = 0; 354222537Sken msglogstr(consbuffer, pri, /*filter_cr*/ 1); 35570239Sphk } 356222537Sken /* 357222537Sken * The previous behavior in log_console() is preserved when 358222537Sken * log_console_add_linefeed is non-zero. For that behavior, if an 359222537Sken * individual console write came in that was not terminated with a 360222537Sken * line feed, it would add a line feed. 361222537Sken * 362222537Sken * This results in different data in the message buffer than 363222537Sken * appears on the system console (which doesn't add extra line feed 364222537Sken * characters). 365222537Sken * 366222537Sken * A number of programs and rc scripts write a line feed, or a period 367222537Sken * and a line feed when they have completed their operation. On 368222537Sken * the console, this looks seamless, but when displayed with 369222537Sken * 'dmesg -a', you wind up with output that looks like this: 370222537Sken * 371222537Sken * Updating motd: 372222537Sken * . 373222537Sken * 374222537Sken * On the console, it looks like this: 375222537Sken * Updating motd:. 376222537Sken * 377222537Sken * We could add logic to detect that situation, or just not insert 378222537Sken * the extra newlines. Set the kern.log_console_add_linefeed 379222537Sken * sysctl/tunable variable to get the old behavior. 380222537Sken */ 381222537Sken if (!nl && log_console_add_linefeed) { 382222537Sken consbuffer[0] = '\n'; 383222537Sken consbuffer[1] = '\0'; 384222537Sken msglogstr(consbuffer, pri, /*filter_cr*/ 1); 385222537Sken } 38670240Sphk msgbuftrigger = 1; 387131897Sphk free(uio, M_IOV); 388131897Sphk free(consbuffer, M_TEMP); 3891541Srgrimes} 3901541Srgrimes 39115680Sgpalmerint 3921541Srgrimesprintf(const char *fmt, ...) 3931541Srgrimes{ 3941541Srgrimes va_list ap; 39513694Sgibbs int retval; 3961541Srgrimes 3971541Srgrimes va_start(ap, fmt); 398189104Sed retval = vprintf(fmt, ap); 3991541Srgrimes va_end(ap); 400163858Sjb 40190490Sphk return (retval); 4021541Srgrimes} 4031541Srgrimes 40449047Sdfrint 40513446Sphkvprintf(const char *fmt, va_list ap) 40613446Sphk{ 40749047Sdfr int retval; 40813446Sphk 409263941Sbdrewery retval = _vprintf(-1, TOCONS | TOLOG, fmt, ap); 410163858Sjb 41113446Sphk if (!panicstr) 41270240Sphk msgbuftrigger = 1; 413163858Sjb 41490490Sphk return (retval); 41513446Sphk} 41613446Sphk 417163858Sjbstatic void 418321108Sngieprf_putbuf(char *bufr, int flags, int pri) 419321108Sngie{ 420321108Sngie 421321108Sngie if (flags & TOLOG) 422321108Sngie msglogstr(bufr, pri, /*filter_cr*/1); 423321108Sngie 424321108Sngie if (flags & TOCONS) { 425321108Sngie if ((panicstr == NULL) && (constty != NULL)) 426321108Sngie msgbuf_addstr(&consmsgbuf, -1, 427321108Sngie bufr, /*filter_cr*/ 0); 428321108Sngie 429321108Sngie if ((constty == NULL) ||(always_console_output)) 430321108Sngie cnputs(bufr); 431321108Sngie } 432321108Sngie} 433321108Sngie 434321108Sngiestatic void 435222537Skenputbuf(int c, struct putchar_arg *ap) 436163858Sjb{ 437163858Sjb /* Check if no console output buffer was provided. */ 438222537Sken if (ap->p_bufr == NULL) { 439163858Sjb /* Output direct to the console. */ 440222537Sken if (ap->flags & TOCONS) 441222537Sken cnputc(c); 442222537Sken 443222537Sken if (ap->flags & TOLOG) 444222537Sken msglogchar(c, ap->pri); 445222537Sken } else { 446163858Sjb /* Buffer the character: */ 447163858Sjb *ap->p_next++ = c; 448163858Sjb ap->remain--; 449163858Sjb 450163858Sjb /* Always leave the buffer zero terminated. */ 451163858Sjb *ap->p_next = '\0'; 452163858Sjb 453163858Sjb /* Check if the buffer needs to be flushed. */ 454222537Sken if (ap->remain == 2 || c == '\n') { 455321108Sngie prf_putbuf(ap->p_bufr, ap->flags, ap->pri); 456222537Sken 457163858Sjb ap->p_next = ap->p_bufr; 458163858Sjb ap->remain = ap->n_bufr; 459163858Sjb *ap->p_next = '\0'; 460163858Sjb } 461222537Sken 462222537Sken /* 463222537Sken * Since we fill the buffer up one character at a time, 464222537Sken * this should not happen. We should always catch it when 465222537Sken * ap->remain == 2 (if not sooner due to a newline), flush 466222537Sken * the buffer and move on. One way this could happen is 467222537Sken * if someone sets PRINTF_BUFR_SIZE to 1 or something 468222537Sken * similarly silly. 469222537Sken */ 470222537Sken KASSERT(ap->remain > 2, ("Bad buffer logic, remain = %zd", 471222537Sken ap->remain)); 472163858Sjb } 473163858Sjb} 474163858Sjb 4751541Srgrimes/* 47613446Sphk * Print a character on console or users terminal. If destination is 47736441Sphk * the console then the last bunch of characters are saved in msgbuf for 47813446Sphk * inspection later. 47913446Sphk */ 48013446Sphkstatic void 48113446Sphkputchar(int c, void *arg) 48213446Sphk{ 48313446Sphk struct putchar_arg *ap = (struct putchar_arg*) arg; 48413446Sphk struct tty *tp = ap->tty; 485163858Sjb int flags = ap->flags; 486116663Siedowse 487116664Siedowse /* Don't use the tty code after a panic or while in ddb. */ 488163858Sjb if (kdb_active) { 489116663Siedowse if (c != '\0') 490116663Siedowse cnputc(c); 491226435Smarcel return; 492226435Smarcel } 493222537Sken 494226435Smarcel if ((flags & TOTTY) && tp != NULL && panicstr == NULL) 495226435Smarcel tty_putchar(tp, c); 496226435Smarcel 497226435Smarcel if ((flags & (TOCONS | TOLOG)) && c != '\0') 498226435Smarcel putbuf(c, ap); 49913446Sphk} 50013446Sphk 50113446Sphk/* 50213446Sphk * Scaled down version of sprintf(3). 50313446Sphk */ 50413446Sphkint 50513446Sphksprintf(char *buf, const char *cfmt, ...) 50613446Sphk{ 50713446Sphk int retval; 50813446Sphk va_list ap; 50913446Sphk 51013446Sphk va_start(ap, cfmt); 51113446Sphk retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 51213494Sphk buf[retval] = '\0'; 51313446Sphk va_end(ap); 51490490Sphk return (retval); 51513446Sphk} 51613446Sphk 51713446Sphk/* 51838874Sache * Scaled down version of vsprintf(3). 51938874Sache */ 52038874Sacheint 52138874Sachevsprintf(char *buf, const char *cfmt, va_list ap) 52238874Sache{ 52338874Sache int retval; 52438874Sache 52538874Sache retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 52638874Sache buf[retval] = '\0'; 52790490Sphk return (retval); 52838874Sache} 52938874Sache 53038874Sache/* 53141479Sarchie * Scaled down version of snprintf(3). 53241479Sarchie */ 53341479Sarchieint 53441479Sarchiesnprintf(char *str, size_t size, const char *format, ...) 53541479Sarchie{ 53641479Sarchie int retval; 53741479Sarchie va_list ap; 53841479Sarchie 53941479Sarchie va_start(ap, format); 54041479Sarchie retval = vsnprintf(str, size, format, ap); 54141479Sarchie va_end(ap); 54241479Sarchie return(retval); 54341479Sarchie} 54441479Sarchie 54541479Sarchie/* 54641479Sarchie * Scaled down version of vsnprintf(3). 54741479Sarchie */ 54841479Sarchieint 54941479Sarchievsnprintf(char *str, size_t size, const char *format, va_list ap) 55041479Sarchie{ 55141479Sarchie struct snprintf_arg info; 55241479Sarchie int retval; 55341479Sarchie 55441479Sarchie info.str = str; 55541479Sarchie info.remain = size; 55641479Sarchie retval = kvprintf(format, snprintf_func, &info, 10, ap); 55741479Sarchie if (info.remain >= 1) 55841479Sarchie *info.str++ = '\0'; 55990490Sphk return (retval); 56041479Sarchie} 56141479Sarchie 562110316Sphk/* 563110316Sphk * Kernel version which takes radix argument vsnprintf(3). 564110316Sphk */ 565110316Sphkint 566110316Sphkvsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap) 567110316Sphk{ 568110316Sphk struct snprintf_arg info; 569110316Sphk int retval; 570110316Sphk 571110316Sphk info.str = str; 572110316Sphk info.remain = size; 573110316Sphk retval = kvprintf(format, snprintf_func, &info, radix, ap); 574110316Sphk if (info.remain >= 1) 575110316Sphk *info.str++ = '\0'; 576110316Sphk return (retval); 577110316Sphk} 578110316Sphk 57941479Sarchiestatic void 58041479Sarchiesnprintf_func(int ch, void *arg) 58141479Sarchie{ 58241479Sarchie struct snprintf_arg *const info = arg; 58341479Sarchie 58441479Sarchie if (info->remain >= 2) { 58541479Sarchie *info->str++ = ch; 58641479Sarchie info->remain--; 58741479Sarchie } 58841479Sarchie} 58941479Sarchie 59041479Sarchie/* 59148728Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 59247822Sarchie * order; return an optional length and a pointer to the last character 59347822Sarchie * written in the buffer (i.e., the first character of the string). 59447822Sarchie * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 59513446Sphk */ 59613446Sphkstatic char * 597156518Sjkimksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 59847822Sarchie{ 599156518Sjkim char *p, c; 60013446Sphk 60147822Sarchie p = nbuf; 60247773Sarchie *p = '\0'; 60313446Sphk do { 604156518Sjkim c = hex2ascii(num % base); 605156518Sjkim *++p = upper ? toupper(c) : c; 60697749Sdes } while (num /= base); 60713446Sphk if (lenp) 60847822Sarchie *lenp = p - nbuf; 60913446Sphk return (p); 61013446Sphk} 61113446Sphk 61213446Sphk/* 6131541Srgrimes * Scaled down version of printf(3). 6141541Srgrimes * 6151541Srgrimes * Two additional formats: 6161541Srgrimes * 6171541Srgrimes * The format %b is supported to decode error registers. 6181541Srgrimes * Its usage is: 6191541Srgrimes * 6201541Srgrimes * printf("reg=%b\n", regval, "<base><arg>*"); 6211541Srgrimes * 6221541Srgrimes * where <base> is the output base expressed as a control character, e.g. 6231541Srgrimes * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 6241541Srgrimes * the first of which gives the bit number to be inspected (origin 1), and 6251541Srgrimes * the next characters (up to a control character, i.e. a character <= 32), 6261541Srgrimes * give the name of the register. Thus: 6271541Srgrimes * 62815700Sgpalmer * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 6291541Srgrimes * 6301541Srgrimes * would produce output: 6311541Srgrimes * 6321541Srgrimes * reg=3<BITTWO,BITONE> 6331541Srgrimes * 63413618Sphk * XXX: %D -- Hexdump, takes pointer and separator string: 63513618Sphk * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 63613618Sphk * ("%*D", len, ptr, " " -> XX XX XX XX ... 6371541Srgrimes */ 63813446Sphkint 63913446Sphkkvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) 6401541Srgrimes{ 64113446Sphk#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } 64247773Sarchie char nbuf[MAXNBUF]; 64397749Sdes char *d; 64497749Sdes const char *p, *percent, *q; 64513618Sphk u_char *up; 64613446Sphk int ch, n; 64797749Sdes uintmax_t num; 64848714Speter int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 649125985Snjl int cflag, hflag, jflag, tflag, zflag; 650156518Sjkim int dwidth, upper; 6511541Srgrimes char padc; 652149756Sphk int stop = 0, retval = 0; 6531541Srgrimes 65497749Sdes num = 0; 65513494Sphk if (!func) 65613446Sphk d = (char *) arg; 65713446Sphk else 65813494Sphk d = NULL; 65913446Sphk 6605261Sdg if (fmt == NULL) 6615288Sbde fmt = "(fmt null)\n"; 66213563Sphk 66313618Sphk if (radix < 2 || radix > 36) 66413563Sphk radix = 10; 66513563Sphk 6661541Srgrimes for (;;) { 6671541Srgrimes padc = ' '; 6681541Srgrimes width = 0; 669149756Sphk while ((ch = (u_char)*fmt++) != '%' || stop) { 67097750Sdes if (ch == '\0') 67190490Sphk return (retval); 67213446Sphk PCHAR(ch); 6731541Srgrimes } 67497749Sdes percent = fmt - 1; 67548714Speter qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 676156518Sjkim sign = 0; dot = 0; dwidth = 0; upper = 0; 677125985Snjl cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 67817974Sbdereswitch: switch (ch = (u_char)*fmt++) { 67913466Sphk case '.': 68013466Sphk dot = 1; 68113466Sphk goto reswitch; 68213446Sphk case '#': 68313446Sphk sharpflag = 1; 68413446Sphk goto reswitch; 68513446Sphk case '+': 68613446Sphk sign = 1; 68713446Sphk goto reswitch; 68813446Sphk case '-': 68913446Sphk ladjust = 1; 69013446Sphk goto reswitch; 69113446Sphk case '%': 69213446Sphk PCHAR(ch); 69313446Sphk break; 69413446Sphk case '*': 69513501Sphk if (!dot) { 69613501Sphk width = va_arg(ap, int); 69713501Sphk if (width < 0) { 69813501Sphk ladjust = !ladjust; 69913501Sphk width = -width; 70013501Sphk } 70113501Sphk } else { 70213501Sphk dwidth = va_arg(ap, int); 70313446Sphk } 70413446Sphk goto reswitch; 7051541Srgrimes case '0': 70613480Sphk if (!dot) { 70713480Sphk padc = '0'; 70813480Sphk goto reswitch; 70913480Sphk } 7101541Srgrimes case '1': case '2': case '3': case '4': 7111541Srgrimes case '5': case '6': case '7': case '8': case '9': 71213480Sphk for (n = 0;; ++fmt) { 71313480Sphk n = n * 10 + ch - '0'; 71413480Sphk ch = *fmt; 71513480Sphk if (ch < '0' || ch > '9') 71613480Sphk break; 71713480Sphk } 71813480Sphk if (dot) 71913480Sphk dwidth = n; 72013480Sphk else 72113480Sphk width = n; 7221541Srgrimes goto reswitch; 7231541Srgrimes case 'b': 724108890Sjhb num = (u_int)va_arg(ap, int); 7251541Srgrimes p = va_arg(ap, char *); 726156518Sjkim for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 72713446Sphk PCHAR(*q--); 7281541Srgrimes 72997749Sdes if (num == 0) 7301541Srgrimes break; 7311541Srgrimes 7323308Sphk for (tmp = 0; *p;) { 7333308Sphk n = *p++; 73497749Sdes if (num & (1 << (n - 1))) { 73513446Sphk PCHAR(tmp ? ',' : '<'); 7361541Srgrimes for (; (n = *p) > ' '; ++p) 73713446Sphk PCHAR(n); 7381541Srgrimes tmp = 1; 7391541Srgrimes } else 7401541Srgrimes for (; *p > ' '; ++p) 7411541Srgrimes continue; 7421541Srgrimes } 7431541Srgrimes if (tmp) 74413446Sphk PCHAR('>'); 7451541Srgrimes break; 7461541Srgrimes case 'c': 74713446Sphk PCHAR(va_arg(ap, int)); 7481541Srgrimes break; 74913618Sphk case 'D': 75013618Sphk up = va_arg(ap, u_char *); 75113618Sphk p = va_arg(ap, char *); 75213618Sphk if (!width) 75313618Sphk width = 16; 75413618Sphk while(width--) { 75513618Sphk PCHAR(hex2ascii(*up >> 4)); 75613618Sphk PCHAR(hex2ascii(*up & 0x0f)); 75713618Sphk up++; 75813618Sphk if (width) 75913618Sphk for (q=p;*q;q++) 76013618Sphk PCHAR(*q); 76113618Sphk } 76213618Sphk break; 7631541Srgrimes case 'd': 76499459Simp case 'i': 76597749Sdes base = 10; 76613446Sphk sign = 1; 76797749Sdes goto handle_sign; 768125985Snjl case 'h': 769125985Snjl if (hflag) { 770125985Snjl hflag = 0; 771125985Snjl cflag = 1; 772125985Snjl } else 773125985Snjl hflag = 1; 774125985Snjl goto reswitch; 77597749Sdes case 'j': 77697749Sdes jflag = 1; 77797749Sdes goto reswitch; 77813446Sphk case 'l': 77949502Sgreen if (lflag) { 78049502Sgreen lflag = 0; 78149502Sgreen qflag = 1; 78249502Sgreen } else 78349502Sgreen lflag = 1; 78413446Sphk goto reswitch; 78597749Sdes case 'n': 78697749Sdes if (jflag) 78797749Sdes *(va_arg(ap, intmax_t *)) = retval; 78897749Sdes else if (qflag) 78997749Sdes *(va_arg(ap, quad_t *)) = retval; 79048714Speter else if (lflag) 79197749Sdes *(va_arg(ap, long *)) = retval; 792105954Smux else if (zflag) 793105954Smux *(va_arg(ap, size_t *)) = retval; 794125985Snjl else if (hflag) 795125985Snjl *(va_arg(ap, short *)) = retval; 796125985Snjl else if (cflag) 797125985Snjl *(va_arg(ap, char *)) = retval; 79848714Speter else 79997749Sdes *(va_arg(ap, int *)) = retval; 80097749Sdes break; 80197749Sdes case 'o': 8021541Srgrimes base = 8; 80397749Sdes goto handle_nosign; 8049224Sbde case 'p': 8059224Sbde base = 16; 80638224Sbde sharpflag = (width == 0); 80797749Sdes sign = 0; 80897749Sdes num = (uintptr_t)va_arg(ap, void *); 80997749Sdes goto number; 81048714Speter case 'q': 81148714Speter qflag = 1; 81248714Speter goto reswitch; 81337505Sbde case 'r': 81437505Sbde base = radix; 81597749Sdes if (sign) 81697749Sdes goto handle_sign; 81797749Sdes goto handle_nosign; 81813446Sphk case 's': 81913446Sphk p = va_arg(ap, char *); 82013446Sphk if (p == NULL) 82113446Sphk p = "(null)"; 82213466Sphk if (!dot) 82313466Sphk n = strlen (p); 82413466Sphk else 82513480Sphk for (n = 0; n < dwidth && p[n]; n++) 82613466Sphk continue; 82713480Sphk 82813466Sphk width -= n; 82913480Sphk 83013446Sphk if (!ladjust && width > 0) 83113446Sphk while (width--) 83213446Sphk PCHAR(padc); 83313466Sphk while (n--) 83413446Sphk PCHAR(*p++); 83513446Sphk if (ladjust && width > 0) 83613446Sphk while (width--) 83713446Sphk PCHAR(padc); 83813446Sphk break; 839106855Smux case 't': 840106855Smux tflag = 1; 841106855Smux goto reswitch; 8421541Srgrimes case 'u': 8431541Srgrimes base = 10; 84497749Sdes goto handle_nosign; 845156518Sjkim case 'X': 846156518Sjkim upper = 1; 8471541Srgrimes case 'x': 8481541Srgrimes base = 16; 84997749Sdes goto handle_nosign; 850105954Smux case 'y': 85197749Sdes base = 16; 852104924Sjhb sign = 1; 853104924Sjhb goto handle_sign; 854105954Smux case 'z': 855105954Smux zflag = 1; 856105954Smux goto reswitch; 85797749Sdeshandle_nosign: 85897749Sdes sign = 0; 85997749Sdes if (jflag) 86097749Sdes num = va_arg(ap, uintmax_t); 86197749Sdes else if (qflag) 86297749Sdes num = va_arg(ap, u_quad_t); 863106855Smux else if (tflag) 864106855Smux num = va_arg(ap, ptrdiff_t); 86548714Speter else if (lflag) 86697749Sdes num = va_arg(ap, u_long); 867105954Smux else if (zflag) 868105954Smux num = va_arg(ap, size_t); 869125985Snjl else if (hflag) 870125985Snjl num = (u_short)va_arg(ap, int); 871125985Snjl else if (cflag) 872125985Snjl num = (u_char)va_arg(ap, int); 87348714Speter else 87497749Sdes num = va_arg(ap, u_int); 87537505Sbde goto number; 87697749Sdeshandle_sign: 87797749Sdes if (jflag) 87897749Sdes num = va_arg(ap, intmax_t); 87997749Sdes else if (qflag) 88097749Sdes num = va_arg(ap, quad_t); 881106855Smux else if (tflag) 882106855Smux num = va_arg(ap, ptrdiff_t); 88397749Sdes else if (lflag) 88497749Sdes num = va_arg(ap, long); 885105954Smux else if (zflag) 886185036Sdelphij num = va_arg(ap, ssize_t); 887125985Snjl else if (hflag) 888125985Snjl num = (short)va_arg(ap, int); 889125985Snjl else if (cflag) 890125985Snjl num = (char)va_arg(ap, int); 89197749Sdes else 89297749Sdes num = va_arg(ap, int); 89397749Sdesnumber: 89497749Sdes if (sign && (intmax_t)num < 0) { 89597749Sdes neg = 1; 89697749Sdes num = -(intmax_t)num; 89713446Sphk } 898209836Sjkim p = ksprintn(nbuf, num, base, &n, upper); 899209836Sjkim tmp = 0; 90097749Sdes if (sharpflag && num != 0) { 90113446Sphk if (base == 8) 90213446Sphk tmp++; 90313446Sphk else if (base == 16) 90413446Sphk tmp += 2; 90513446Sphk } 90613446Sphk if (neg) 90713446Sphk tmp++; 90813446Sphk 909209836Sjkim if (!ladjust && padc == '0') 910209836Sjkim dwidth = width - tmp; 911209949Sjkim width -= tmp + imax(dwidth, n); 912209836Sjkim dwidth -= n; 913209836Sjkim if (!ladjust) 914209836Sjkim while (width-- > 0) 915209836Sjkim PCHAR(' '); 91613446Sphk if (neg) 91713446Sphk PCHAR('-'); 91897749Sdes if (sharpflag && num != 0) { 91913446Sphk if (base == 8) { 92013446Sphk PCHAR('0'); 92113446Sphk } else if (base == 16) { 92213446Sphk PCHAR('0'); 92313446Sphk PCHAR('x'); 92413446Sphk } 92513446Sphk } 926209836Sjkim while (dwidth-- > 0) 927209836Sjkim PCHAR('0'); 92813446Sphk 9293308Sphk while (*p) 93013446Sphk PCHAR(*p--); 93113446Sphk 932209836Sjkim if (ladjust) 933209836Sjkim while (width-- > 0) 934209836Sjkim PCHAR(' '); 93513446Sphk 9361541Srgrimes break; 9371541Srgrimes default: 93897749Sdes while (percent < fmt) 93997749Sdes PCHAR(*percent++); 940149756Sphk /* 941266026Sbdrewery * Since we ignore a formatting argument it is no 942149756Sphk * longer safe to obey the remaining formatting 943149756Sphk * arguments as the arguments will no longer match 944149756Sphk * the format specs. 945149756Sphk */ 946149756Sphk stop = 1; 94713446Sphk break; 9481541Srgrimes } 9491541Srgrimes } 95013446Sphk#undef PCHAR 9511541Srgrimes} 9521541Srgrimes 9531541Srgrimes/* 95470239Sphk * Put character in log buffer with a particular priority. 9551541Srgrimes */ 9561541Srgrimesstatic void 95770239Sphkmsglogchar(int c, int pri) 9581541Srgrimes{ 95970239Sphk static int lastpri = -1; 96070239Sphk static int dangling; 96170239Sphk char nbuf[MAXNBUF]; 96270239Sphk char *p; 9631541Srgrimes 96470239Sphk if (!msgbufmapped) 96570239Sphk return; 96670239Sphk if (c == '\0' || c == '\r') 96770239Sphk return; 96870239Sphk if (pri != -1 && pri != lastpri) { 96970239Sphk if (dangling) { 970116660Siedowse msgbuf_addchar(msgbufp, '\n'); 97170239Sphk dangling = 0; 9726561Sbde } 973116660Siedowse msgbuf_addchar(msgbufp, '<'); 974156518Sjkim for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL, 0); *p;) 975116660Siedowse msgbuf_addchar(msgbufp, *p--); 976116660Siedowse msgbuf_addchar(msgbufp, '>'); 97770239Sphk lastpri = pri; 9781541Srgrimes } 979116660Siedowse msgbuf_addchar(msgbufp, c); 98070239Sphk if (c == '\n') { 98170239Sphk dangling = 0; 98270239Sphk lastpri = -1; 98370239Sphk } else { 98470239Sphk dangling = 1; 98570239Sphk } 9861541Srgrimes} 98736441Sphk 988222537Skenstatic void 989222537Skenmsglogstr(char *str, int pri, int filter_cr) 990222537Sken{ 991222537Sken if (!msgbufmapped) 992222537Sken return; 993222537Sken 994222537Sken msgbuf_addstr(msgbufp, pri, str, filter_cr); 995222537Sken} 996222537Sken 99736441Sphkvoid 998106917Stmmmsgbufinit(void *ptr, int size) 99936441Sphk{ 100036441Sphk char *cp; 100147678Sjlemon static struct msgbuf *oldp = NULL; 100236441Sphk 100386238Siedowse size -= sizeof(*msgbufp); 100436441Sphk cp = (char *)ptr; 1005116660Siedowse msgbufp = (struct msgbuf *)(cp + size); 1006116660Siedowse msgbuf_reinit(msgbufp, cp, size); 100747678Sjlemon if (msgbufmapped && oldp != msgbufp) 1008116660Siedowse msgbuf_copy(oldp, msgbufp); 100936441Sphk msgbufmapped = 1; 101047678Sjlemon oldp = msgbufp; 101136441Sphk} 101236441Sphk 101387150Srwatsonstatic int unprivileged_read_msgbuf = 1; 101489414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf, 101587150Srwatson CTLFLAG_RW, &unprivileged_read_msgbuf, 0, 101687150Srwatson "Unprivileged processes may read the kernel message buffer"); 101787150Srwatson 101879153Stmm/* Sysctls for accessing/clearing the msgbuf */ 101979153Stmmstatic int 102079153Stmmsysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS) 102179153Stmm{ 1022116660Siedowse char buf[128]; 1023116660Siedowse u_int seq; 1024116660Siedowse int error, len; 102579153Stmm 102687150Srwatson if (!unprivileged_read_msgbuf) { 1027164033Srwatson error = priv_check(req->td, PRIV_MSGBUF); 102887150Srwatson if (error) 102987150Srwatson return (error); 103087150Srwatson } 103187150Srwatson 1032116660Siedowse /* Read the whole buffer, one chunk at a time. */ 1033198860Sed mtx_lock(&msgbuf_lock); 1034116660Siedowse msgbuf_peekbytes(msgbufp, NULL, 0, &seq); 1035198860Sed for (;;) { 1036198860Sed len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq); 1037198860Sed mtx_unlock(&msgbuf_lock); 1038198860Sed if (len == 0) 1039198860Sed return (0); 1040198860Sed 1041116660Siedowse error = sysctl_handle_opaque(oidp, buf, len, req); 1042116660Siedowse if (error) 1043116660Siedowse return (error); 1044198860Sed 1045198860Sed mtx_lock(&msgbuf_lock); 104679153Stmm } 104779153Stmm} 104879153Stmm 1049198860SedSYSCTL_PROC(_kern, OID_AUTO, msgbuf, 1050198860Sed CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 1051188057Simp NULL, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer"); 105279153Stmm 1053116660Siedowsestatic int msgbuf_clearflag; 105479153Stmm 105579153Stmmstatic int 105679153Stmmsysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS) 105779153Stmm{ 105879153Stmm int error; 105979153Stmm error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); 106079153Stmm if (!error && req->newptr) { 1061198860Sed mtx_lock(&msgbuf_lock); 1062116660Siedowse msgbuf_clear(msgbufp); 1063198860Sed mtx_unlock(&msgbuf_lock); 1064116660Siedowse msgbuf_clearflag = 0; 106579153Stmm } 106679153Stmm return (error); 106779153Stmm} 106879153Stmm 106979153StmmSYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear, 1070198860Sed CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_MPSAFE, 1071198860Sed &msgbuf_clearflag, 0, sysctl_kern_msgbuf_clear, "I", 1072198860Sed "Clear kernel message buffer"); 107379153Stmm 107436441Sphk#ifdef DDB 107536441Sphk 107636441SphkDB_SHOW_COMMAND(msgbuf, db_show_msgbuf) 107736441Sphk{ 1078160312Sjhb int i, j; 107936441Sphk 108036441Sphk if (!msgbufmapped) { 108136441Sphk db_printf("msgbuf not mapped yet\n"); 108236441Sphk return; 108336441Sphk } 108436441Sphk db_printf("msgbufp = %p\n", msgbufp); 1085116660Siedowse db_printf("magic = %x, size = %d, r= %u, w = %u, ptr = %p, cksum= %u\n", 1086116660Siedowse msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_rseq, 1087116660Siedowse msgbufp->msg_wseq, msgbufp->msg_ptr, msgbufp->msg_cksum); 1088160312Sjhb for (i = 0; i < msgbufp->msg_size && !db_pager_quit; i++) { 1089116660Siedowse j = MSGBUF_SEQ_TO_POS(msgbufp, i + msgbufp->msg_rseq); 109036441Sphk db_printf("%c", msgbufp->msg_ptr[j]); 109136441Sphk } 109236441Sphk db_printf("\n"); 109336441Sphk} 109436441Sphk 109536441Sphk#endif /* DDB */ 1096123215Sscottl 1097123215Sscottlvoid 1098144706Sphkhexdump(const void *ptr, int length, const char *hdr, int flags) 1099123215Sscottl{ 1100123215Sscottl int i, j, k; 1101123215Sscottl int cols; 1102144706Sphk const unsigned char *cp; 1103123215Sscottl char delim; 1104123215Sscottl 1105123215Sscottl if ((flags & HD_DELIM_MASK) != 0) 1106123215Sscottl delim = (flags & HD_DELIM_MASK) >> 8; 1107123215Sscottl else 1108123215Sscottl delim = ' '; 1109123215Sscottl 1110123215Sscottl if ((flags & HD_COLUMN_MASK) != 0) 1111123215Sscottl cols = flags & HD_COLUMN_MASK; 1112123215Sscottl else 1113123215Sscottl cols = 16; 1114123215Sscottl 1115123215Sscottl cp = ptr; 1116123215Sscottl for (i = 0; i < length; i+= cols) { 1117123215Sscottl if (hdr != NULL) 1118123215Sscottl printf("%s", hdr); 1119123215Sscottl 1120123215Sscottl if ((flags & HD_OMIT_COUNT) == 0) 1121123215Sscottl printf("%04x ", i); 1122123215Sscottl 1123123215Sscottl if ((flags & HD_OMIT_HEX) == 0) { 1124123215Sscottl for (j = 0; j < cols; j++) { 1125123215Sscottl k = i + j; 1126123215Sscottl if (k < length) 1127123215Sscottl printf("%c%02x", delim, cp[k]); 1128123215Sscottl else 1129123215Sscottl printf(" "); 1130123215Sscottl } 1131123215Sscottl } 1132123215Sscottl 1133123215Sscottl if ((flags & HD_OMIT_CHARS) == 0) { 1134123215Sscottl printf(" |"); 1135123215Sscottl for (j = 0; j < cols; j++) { 1136123215Sscottl k = i + j; 1137123215Sscottl if (k >= length) 1138123215Sscottl printf(" "); 1139123215Sscottl else if (cp[k] >= ' ' && cp[k] <= '~') 1140123215Sscottl printf("%c", cp[k]); 1141123215Sscottl else 1142123215Sscottl printf("."); 1143123215Sscottl } 1144156001Sscottl printf("|"); 1145123215Sscottl } 1146156001Sscottl printf("\n"); 1147123215Sscottl } 1148123215Sscottl} 1149284435Sken#endif /* _KERNEL */ 1150284435Sken 1151284435Skenvoid 1152284435Skensbuf_hexdump(struct sbuf *sb, const void *ptr, int length, const char *hdr, 1153284435Sken int flags) 1154284435Sken{ 1155284435Sken int i, j, k; 1156284435Sken int cols; 1157284435Sken const unsigned char *cp; 1158284435Sken char delim; 1159284435Sken 1160284435Sken if ((flags & HD_DELIM_MASK) != 0) 1161284435Sken delim = (flags & HD_DELIM_MASK) >> 8; 1162284435Sken else 1163284435Sken delim = ' '; 1164284435Sken 1165284435Sken if ((flags & HD_COLUMN_MASK) != 0) 1166284435Sken cols = flags & HD_COLUMN_MASK; 1167284435Sken else 1168284435Sken cols = 16; 1169284435Sken 1170284435Sken cp = ptr; 1171284435Sken for (i = 0; i < length; i+= cols) { 1172284435Sken if (hdr != NULL) 1173284435Sken sbuf_printf(sb, "%s", hdr); 1174284435Sken 1175284435Sken if ((flags & HD_OMIT_COUNT) == 0) 1176284435Sken sbuf_printf(sb, "%04x ", i); 1177284435Sken 1178284435Sken if ((flags & HD_OMIT_HEX) == 0) { 1179284435Sken for (j = 0; j < cols; j++) { 1180284435Sken k = i + j; 1181284435Sken if (k < length) 1182284435Sken sbuf_printf(sb, "%c%02x", delim, cp[k]); 1183284435Sken else 1184284435Sken sbuf_printf(sb, " "); 1185284435Sken } 1186284435Sken } 1187284435Sken 1188284435Sken if ((flags & HD_OMIT_CHARS) == 0) { 1189284435Sken sbuf_printf(sb, " |"); 1190284435Sken for (j = 0; j < cols; j++) { 1191284435Sken k = i + j; 1192284435Sken if (k >= length) 1193284435Sken sbuf_printf(sb, " "); 1194284435Sken else if (cp[k] >= ' ' && cp[k] <= '~') 1195284435Sken sbuf_printf(sb, "%c", cp[k]); 1196284435Sken else 1197284435Sken sbuf_printf(sb, "."); 1198284435Sken } 1199284435Sken sbuf_printf(sb, "|"); 1200284435Sken } 1201284435Sken sbuf_printf(sb, "\n"); 1202284435Sken } 1203284435Sken} 1204284435Sken 1205303433Skib#ifdef _KERNEL 1206303433Skibvoid 1207303433Skibcounted_warning(unsigned *counter, const char *msg) 1208303433Skib{ 1209303433Skib struct thread *td; 1210303433Skib unsigned c; 1211303433Skib 1212303433Skib for (;;) { 1213303433Skib c = *counter; 1214303433Skib if (c == 0) 1215303433Skib break; 1216303433Skib if (atomic_cmpset_int(counter, c, c - 1)) { 1217303433Skib td = curthread; 1218303433Skib log(LOG_INFO, "pid %d (%s) %s%s\n", 1219303433Skib td->td_proc->p_pid, td->td_name, msg, 1220303433Skib c > 1 ? "" : " - not logging anymore"); 1221303433Skib break; 1222303433Skib } 1223303433Skib } 1224303433Skib} 1225303433Skib#endif 1226321108Sngie 1227321108Sngie#ifdef _KERNEL 1228321108Sngievoid 1229321108Sngiesbuf_putbuf(struct sbuf *sb) 1230321108Sngie{ 1231321108Sngie 1232321108Sngie prf_putbuf(sbuf_data(sb), TOLOG | TOCONS, -1); 1233321108Sngie} 1234321108Sngie#else 1235321108Sngievoid 1236321108Sngiesbuf_putbuf(struct sbuf *sb) 1237321108Sngie{ 1238321108Sngie 1239321108Sngie printf("%s", sbuf_data(sb)); 1240321108Sngie} 1241321108Sngie#endif 1242