hexdump.c revision 3174
1/*-
2 * Copyright (c) 1986, 1988, 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
39 * $Id: subr_prf.c,v 1.5 1994/08/27 16:14:27 davidg Exp $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/buf.h>
45#include <sys/conf.h>
46#include <sys/reboot.h>
47#include <sys/msgbuf.h>
48#include <sys/proc.h>
49#include <sys/ioctl.h>
50#include <sys/vnode.h>
51#include <sys/file.h>
52#include <sys/tty.h>
53#include <sys/tprintf.h>
54#include <sys/syslog.h>
55#include <sys/malloc.h>
56
57/*
58 * Note that stdarg.h and the ANSI style va_start macro is used for both
59 * ANSI and traditional C compilers.
60 */
61#include <machine/stdarg.h>
62
63#ifdef KADB
64#include <machine/kdbparam.h>
65#endif
66
67#define TOCONS	0x01
68#define TOTTY	0x02
69#define TOLOG	0x04
70
71struct	tty *constty;			/* pointer to console "window" tty */
72
73extern	cnputc();			/* standard console putc */
74int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
75
76void  logpri __P((int level));
77static void  putchar __P((int ch, int flags, struct tty *tp));
78static char *ksprintn __P((u_long num, int base, int *len));
79void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap));
80
81int consintr = 1;			/* Ok to handle console interrupts? */
82
83/*
84 * Variable panicstr contains argument to first call to panic; used as flag
85 * to indicate that the kernel has already called panic.
86 */
87const char *panicstr;
88
89/*
90 * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
91 * and then reboots.  If we are called twice, then we avoid trying to sync
92 * the disks as this often leads to recursive panics.
93 */
94#ifdef __GNUC__
95__dead			/* panic() does not return */
96#endif
97void
98#ifdef __STDC__
99panic(const char *fmt, ...)
100#else
101panic(fmt, va_alist)
102	char *fmt;
103#endif
104{
105	int bootopt;
106	va_list ap;
107
108	bootopt = RB_AUTOBOOT | RB_DUMP;
109	if (panicstr)
110		bootopt |= RB_NOSYNC;
111	else
112		panicstr = fmt;
113
114	va_start(ap, fmt);
115	printf("panic: %r\n", fmt, ap);
116	va_end(ap);
117
118#ifdef KGDB
119	kgdb_panic();
120#endif
121#ifdef KADB
122	if (boothowto & RB_KDB)
123		kdbpanic();
124#endif
125#ifdef DDB
126	Debugger ("panic");
127#endif
128	boot(bootopt);
129}
130
131/*
132 * Warn that a system table is full.
133 */
134void
135tablefull(tab)
136	const char *tab;
137{
138
139	log(LOG_ERR, "%s: table is full\n", tab);
140}
141
142/*
143 * Uprintf prints to the controlling terminal for the current process.
144 * It may block if the tty queue is overfull.  No message is printed if
145 * the queue does not clear in a reasonable time.
146 */
147void
148#ifdef __STDC__
149uprintf(const char *fmt, ...)
150#else
151uprintf(fmt, va_alist)
152	char *fmt;
153#endif
154{
155	register struct proc *p = curproc;
156	va_list ap;
157
158	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
159		va_start(ap, fmt);
160		kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
161		va_end(ap);
162	}
163}
164
165tpr_t
166tprintf_open(p)
167	register struct proc *p;
168{
169
170	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
171		SESSHOLD(p->p_session);
172		return ((tpr_t) p->p_session);
173	}
174	return ((tpr_t) NULL);
175}
176
177void
178tprintf_close(sess)
179	tpr_t sess;
180{
181
182	if (sess)
183		SESSRELE((struct session *) sess);
184}
185
186/*
187 * tprintf prints on the controlling terminal associated
188 * with the given session.
189 */
190void
191#ifdef __STDC__
192tprintf(tpr_t tpr, const char *fmt, ...)
193#else
194tprintf(tpr, fmt, va_alist)
195	tpr_t tpr;
196	char *fmt;
197#endif
198{
199	register struct session *sess = (struct session *)tpr;
200	struct tty *tp = NULL;
201	int flags = TOLOG;
202	va_list ap;
203
204	logpri(LOG_INFO);
205	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
206		flags |= TOTTY;
207		tp = sess->s_ttyp;
208	}
209	va_start(ap, fmt);
210	kprintf(fmt, flags, tp, ap);
211	va_end(ap);
212	logwakeup();
213}
214
215/*
216 * Ttyprintf displays a message on a tty; it should be used only by
217 * the tty driver, or anything that knows the underlying tty will not
218 * be revoke(2)'d away.  Other callers should use tprintf.
219 */
220void
221#ifdef __STDC__
222ttyprintf(struct tty *tp, const char *fmt, ...)
223#else
224ttyprintf(tp, fmt, va_alist)
225	struct tty *tp;
226	char *fmt;
227#endif
228{
229	va_list ap;
230
231	va_start(ap, fmt);
232	kprintf(fmt, TOTTY, tp, ap);
233	va_end(ap);
234}
235
236extern	int log_open;
237
238/*
239 * Log writes to the log buffer, and guarantees not to sleep (so can be
240 * called by interrupt routines).  If there is no process reading the
241 * log yet, it writes to the console also.
242 */
243void
244#ifdef __STDC__
245log(int level, const char *fmt, ...)
246#else
247log(level, fmt, va_alist)
248	int level;
249	char *fmt;
250#endif
251{
252	register int s;
253	va_list ap;
254
255	s = splhigh();
256	logpri(level);
257	va_start(ap, fmt);
258	kprintf(fmt, TOLOG, NULL, ap);
259	splx(s);
260	va_end(ap);
261	if (!log_open) {
262		va_start(ap, fmt);
263		kprintf(fmt, TOCONS, NULL, ap);
264		va_end(ap);
265	}
266	logwakeup();
267}
268
269void
270logpri(level)
271	int level;
272{
273	register int ch;
274	register char *p;
275
276	putchar('<', TOLOG, NULL);
277	for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
278		putchar(ch, TOLOG, NULL);
279	putchar('>', TOLOG, NULL);
280}
281
282void
283#ifdef __STDC__
284addlog(const char *fmt, ...)
285#else
286addlog(fmt, va_alist)
287	char *fmt;
288#endif
289{
290	register int s;
291	va_list ap;
292
293	s = splhigh();
294	va_start(ap, fmt);
295	kprintf(fmt, TOLOG, NULL, ap);
296	splx(s);
297	va_end(ap);
298	if (!log_open) {
299		va_start(ap, fmt);
300		kprintf(fmt, TOCONS, NULL, ap);
301		va_end(ap);
302	}
303	logwakeup();
304}
305
306void
307#ifdef __STDC__
308printf(const char *fmt, ...)
309#else
310printf(fmt, va_alist)
311	char *fmt;
312#endif
313{
314	va_list ap;
315	register int savintr;
316
317	savintr = consintr;		/* disable interrupts */
318	consintr = 0;
319	va_start(ap, fmt);
320	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
321	va_end(ap);
322	if (!panicstr)
323		logwakeup();
324	consintr = savintr;		/* reenable interrupts */
325}
326
327/*
328 * Scaled down version of printf(3).
329 *
330 * Two additional formats:
331 *
332 * The format %b is supported to decode error registers.
333 * Its usage is:
334 *
335 *	printf("reg=%b\n", regval, "<base><arg>*");
336 *
337 * where <base> is the output base expressed as a control character, e.g.
338 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
339 * the first of which gives the bit number to be inspected (origin 1), and
340 * the next characters (up to a control character, i.e. a character <= 32),
341 * give the name of the register.  Thus:
342 *
343 *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
344 *
345 * would produce output:
346 *
347 *	reg=3<BITTWO,BITONE>
348 *
349 * The format %r passes an additional format string and argument list
350 * recursively.  Its usage is:
351 *
352 * fn(char *fmt, ...)
353 * {
354 *	va_list ap;
355 *	va_start(ap, fmt);
356 *	printf("prefix: %r: suffix\n", fmt, ap);
357 *	va_end(ap);
358 * }
359 *
360 * Space or zero padding and a field width are supported for the numeric
361 * formats only.
362 */
363void
364kprintf(fmt, flags, tp, ap)
365	register const char *fmt;
366	int flags;
367	struct tty *tp;
368	va_list ap;
369{
370	register char *p, *q;
371	register int ch, n;
372	u_long ul;
373	int base, lflag, tmp, width;
374	char padc;
375
376	for (;;) {
377		padc = ' ';
378		width = 0;
379		while ((ch = *(u_char *)fmt++) != '%') {
380			if (ch == '\0')
381				return;
382			putchar(ch, flags, tp);
383		}
384		lflag = 0;
385reswitch:	switch (ch = *(u_char *)fmt++) {
386		case '0':
387			padc = '0';
388			goto reswitch;
389		case '1': case '2': case '3': case '4':
390		case '5': case '6': case '7': case '8': case '9':
391			for (width = 0;; ++fmt) {
392				width = width * 10 + ch - '0';
393				ch = *fmt;
394				if (ch < '0' || ch > '9')
395					break;
396			}
397			goto reswitch;
398		case 'l':
399			lflag = 1;
400			goto reswitch;
401		case 'b':
402			ul = va_arg(ap, int);
403			p = va_arg(ap, char *);
404			for (q = ksprintn(ul, *p++, NULL); ch = *q--;)
405				putchar(ch, flags, tp);
406
407			if (!ul)
408				break;
409
410			for (tmp = 0; n = *p++;) {
411				if (ul & (1 << (n - 1))) {
412					putchar(tmp ? ',' : '<', flags, tp);
413					for (; (n = *p) > ' '; ++p)
414						putchar(n, flags, tp);
415					tmp = 1;
416				} else
417					for (; *p > ' '; ++p)
418						continue;
419			}
420			if (tmp)
421				putchar('>', flags, tp);
422			break;
423		case 'c':
424			putchar(va_arg(ap, int), flags, tp);
425			break;
426		case 'r':
427			p = va_arg(ap, char *);
428			kprintf(p, flags, tp, va_arg(ap, va_list));
429			break;
430		case 's':
431			p = va_arg(ap, char *);
432			while (ch = *p++)
433				putchar(ch, flags, tp);
434			break;
435		case 'd':
436			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
437			if ((long)ul < 0) {
438				putchar('-', flags, tp);
439				ul = -(long)ul;
440			}
441			base = 10;
442			goto number;
443		case 'o':
444			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
445			base = 8;
446			goto number;
447		case 'u':
448			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
449			base = 10;
450			goto number;
451		case 'p':
452			ul = (u_long) va_arg(ap, void *);
453			width=8;
454			base=16;
455			putchar('0',flags,tp);
456			putchar('x',flags,tp);
457			goto number;
458		case 'x':
459			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
460			base = 16;
461number:			p = ksprintn(ul, base, &tmp);
462			if (width && (width -= tmp) > 0)
463				while (width--)
464					putchar(padc, flags, tp);
465			while (ch = *p--)
466				putchar(ch, flags, tp);
467			break;
468		default:
469			putchar('%', flags, tp);
470			if (lflag)
471				putchar('l', flags, tp);
472			/* FALLTHROUGH */
473		case '%':
474			putchar(ch, flags, tp);
475		}
476	}
477}
478
479/*
480 * Print a character on console or users terminal.  If destination is
481 * the console then the last MSGBUFS characters are saved in msgbuf for
482 * inspection later.
483 */
484static void
485putchar(c, flags, tp)
486	register int c;
487	int flags;
488	struct tty *tp;
489{
490	extern int msgbufmapped;
491	register struct msgbuf *mbp;
492
493	if (panicstr)
494		constty = NULL;
495	if ((flags & TOCONS) && tp == NULL && constty) {
496		tp = constty;
497		flags |= TOTTY;
498	}
499	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
500	    (flags & TOCONS) && tp == constty)
501		constty = NULL;
502	if ((flags & TOLOG) &&
503	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
504		mbp = msgbufp;
505		if (mbp->msg_magic != MSG_MAGIC) {
506			bzero((caddr_t)mbp, sizeof(*mbp));
507			mbp->msg_magic = MSG_MAGIC;
508		}
509		mbp->msg_bufc[mbp->msg_bufx++] = c;
510		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
511			mbp->msg_bufx = 0;
512	}
513	if ((flags & TOCONS) && constty == NULL && c != '\0')
514		(*v_putc)(c);
515}
516
517/*
518 * Scaled down version of sprintf(3).
519 */
520#ifdef __STDC__
521int
522sprintf(char *buf, const char *cfmt, ...)
523#else
524int
525sprintf(buf, cfmt, va_alist)
526	char *buf, *cfmt;
527#endif
528{
529	register const char *fmt = cfmt;
530	register char *p, *bp;
531	register int ch, base;
532	u_long ul;
533	int lflag;
534	va_list ap;
535
536	va_start(ap, cfmt);
537	for (bp = buf; ; ) {
538		while ((ch = *(u_char *)fmt++) != '%')
539			if ((*bp++ = ch) == '\0')
540				return ((bp - buf) - 1);
541
542		lflag = 0;
543reswitch:	switch (ch = *(u_char *)fmt++) {
544		case 'l':
545			lflag = 1;
546			goto reswitch;
547		case 'c':
548			*bp++ = va_arg(ap, int);
549			break;
550		case 's':
551			p = va_arg(ap, char *);
552			while (*bp++ = *p++)
553				continue;
554			--bp;
555			break;
556		case 'd':
557			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
558			if ((long)ul < 0) {
559				*bp++ = '-';
560				ul = -(long)ul;
561			}
562			base = 10;
563			goto number;
564			break;
565		case 'o':
566			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
567			base = 8;
568			goto number;
569			break;
570		case 'u':
571			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
572			base = 10;
573			goto number;
574			break;
575		case 'x':
576			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
577			base = 16;
578number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
579				*bp++ = ch;
580			break;
581		default:
582			*bp++ = '%';
583			if (lflag)
584				*bp++ = 'l';
585			/* FALLTHROUGH */
586		case '%':
587			*bp++ = ch;
588		}
589	}
590	va_end(ap);
591}
592
593/*
594 * Put a number (base <= 16) in a buffer in reverse order; return an
595 * optional length and a pointer to the NULL terminated (preceded?)
596 * buffer.
597 */
598static char *
599ksprintn(ul, base, lenp)
600	register u_long ul;
601	register int base, *lenp;
602{					/* A long in base 8, plus NULL. */
603	static char buf[sizeof(long) * NBBY / 3 + 2];
604	register char *p;
605
606	p = buf;
607	do {
608		*++p = "0123456789abcdef"[ul % base];
609	} while (ul /= base);
610	if (lenp)
611		*lenp = p - buf;
612	return (p);
613}
614