hexdump.c revision 2320
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.4 1994/08/13 14:21:51 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 'x':
452			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
453			base = 16;
454number:			p = ksprintn(ul, base, &tmp);
455			if (width && (width -= tmp) > 0)
456				while (width--)
457					putchar(padc, flags, tp);
458			while (ch = *p--)
459				putchar(ch, flags, tp);
460			break;
461		default:
462			putchar('%', flags, tp);
463			if (lflag)
464				putchar('l', flags, tp);
465			/* FALLTHROUGH */
466		case '%':
467			putchar(ch, flags, tp);
468		}
469	}
470}
471
472/*
473 * Print a character on console or users terminal.  If destination is
474 * the console then the last MSGBUFS characters are saved in msgbuf for
475 * inspection later.
476 */
477static void
478putchar(c, flags, tp)
479	register int c;
480	int flags;
481	struct tty *tp;
482{
483	extern int msgbufmapped;
484	register struct msgbuf *mbp;
485
486	if (panicstr)
487		constty = NULL;
488	if ((flags & TOCONS) && tp == NULL && constty) {
489		tp = constty;
490		flags |= TOTTY;
491	}
492	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
493	    (flags & TOCONS) && tp == constty)
494		constty = NULL;
495	if ((flags & TOLOG) &&
496	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
497		mbp = msgbufp;
498		if (mbp->msg_magic != MSG_MAGIC) {
499			bzero((caddr_t)mbp, sizeof(*mbp));
500			mbp->msg_magic = MSG_MAGIC;
501		}
502		mbp->msg_bufc[mbp->msg_bufx++] = c;
503		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
504			mbp->msg_bufx = 0;
505	}
506	if ((flags & TOCONS) && constty == NULL && c != '\0')
507		(*v_putc)(c);
508}
509
510/*
511 * Scaled down version of sprintf(3).
512 */
513#ifdef __STDC__
514int
515sprintf(char *buf, const char *cfmt, ...)
516#else
517int
518sprintf(buf, cfmt, va_alist)
519	char *buf, *cfmt;
520#endif
521{
522	register const char *fmt = cfmt;
523	register char *p, *bp;
524	register int ch, base;
525	u_long ul;
526	int lflag;
527	va_list ap;
528
529	va_start(ap, cfmt);
530	for (bp = buf; ; ) {
531		while ((ch = *(u_char *)fmt++) != '%')
532			if ((*bp++ = ch) == '\0')
533				return ((bp - buf) - 1);
534
535		lflag = 0;
536reswitch:	switch (ch = *(u_char *)fmt++) {
537		case 'l':
538			lflag = 1;
539			goto reswitch;
540		case 'c':
541			*bp++ = va_arg(ap, int);
542			break;
543		case 's':
544			p = va_arg(ap, char *);
545			while (*bp++ = *p++)
546				continue;
547			--bp;
548			break;
549		case 'd':
550			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
551			if ((long)ul < 0) {
552				*bp++ = '-';
553				ul = -(long)ul;
554			}
555			base = 10;
556			goto number;
557			break;
558		case 'o':
559			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
560			base = 8;
561			goto number;
562			break;
563		case 'u':
564			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
565			base = 10;
566			goto number;
567			break;
568		case 'x':
569			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
570			base = 16;
571number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
572				*bp++ = ch;
573			break;
574		default:
575			*bp++ = '%';
576			if (lflag)
577				*bp++ = 'l';
578			/* FALLTHROUGH */
579		case '%':
580			*bp++ = ch;
581		}
582	}
583	va_end(ap);
584}
585
586/*
587 * Put a number (base <= 16) in a buffer in reverse order; return an
588 * optional length and a pointer to the NULL terminated (preceded?)
589 * buffer.
590 */
591static char *
592ksprintn(ul, base, lenp)
593	register u_long ul;
594	register int base, *lenp;
595{					/* A long in base 8, plus NULL. */
596	static char buf[sizeof(long) * NBBY / 3 + 2];
597	register char *p;
598
599	p = buf;
600	do {
601		*++p = "0123456789abcdef"[ul % base];
602	} while (ul /= base);
603	if (lenp)
604		*lenp = p - buf;
605	return (p);
606}
607