hexdump.c revision 6561
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.9 1994/12/30 12:17:42 bde 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 char *p;
274
275	putchar('<', TOLOG, NULL);
276	for (p = ksprintn((u_long)level, 10, NULL); *p;)
277		putchar(*p--, TOLOG, NULL);
278	putchar('>', TOLOG, NULL);
279}
280
281void
282#ifdef __STDC__
283addlog(const char *fmt, ...)
284#else
285addlog(fmt, va_alist)
286	char *fmt;
287#endif
288{
289	register int s;
290	va_list ap;
291
292	s = splhigh();
293	va_start(ap, fmt);
294	kprintf(fmt, TOLOG, NULL, ap);
295	splx(s);
296	va_end(ap);
297	if (!log_open) {
298		va_start(ap, fmt);
299		kprintf(fmt, TOCONS, NULL, ap);
300		va_end(ap);
301	}
302	logwakeup();
303}
304
305void
306#ifdef __STDC__
307printf(const char *fmt, ...)
308#else
309printf(fmt, va_alist)
310	char *fmt;
311#endif
312{
313	va_list ap;
314	register int savintr;
315
316	savintr = consintr;		/* disable interrupts */
317	consintr = 0;
318	va_start(ap, fmt);
319	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
320	va_end(ap);
321	if (!panicstr)
322		logwakeup();
323	consintr = savintr;		/* reenable interrupts */
324}
325
326/*
327 * Scaled down version of printf(3).
328 *
329 * Two additional formats:
330 *
331 * The format %b is supported to decode error registers.
332 * Its usage is:
333 *
334 *	printf("reg=%b\n", regval, "<base><arg>*");
335 *
336 * where <base> is the output base expressed as a control character, e.g.
337 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
338 * the first of which gives the bit number to be inspected (origin 1), and
339 * the next characters (up to a control character, i.e. a character <= 32),
340 * give the name of the register.  Thus:
341 *
342 *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
343 *
344 * would produce output:
345 *
346 *	reg=3<BITTWO,BITONE>
347 *
348 * The format %r passes an additional format string and argument list
349 * recursively.  Its usage is:
350 *
351 * fn(char *fmt, ...)
352 * {
353 *	va_list ap;
354 *	va_start(ap, fmt);
355 *	printf("prefix: %r: suffix\n", fmt, ap);
356 *	va_end(ap);
357 * }
358 *
359 * Space or zero padding and a field width are supported for the numeric
360 * formats only.
361 */
362void
363kprintf(fmt, flags, tp, ap)
364	register const char *fmt;
365	int flags;
366	struct tty *tp;
367	va_list ap;
368{
369	register char *p, *q;
370	register int ch, n;
371	u_long ul;
372	int base, lflag, tmp, width;
373	char padc;
374
375	if (fmt == NULL)
376		fmt = "(fmt null)\n";
377	for (;;) {
378		padc = ' ';
379		width = 0;
380		while ((ch = *(u_char *)fmt++) != '%') {
381			if (ch == '\0')
382				return;
383			putchar(ch, flags, tp);
384		}
385		lflag = 0;
386reswitch:	switch (ch = *(u_char *)fmt++) {
387		case '0':
388			padc = '0';
389			goto reswitch;
390		case '1': case '2': case '3': case '4':
391		case '5': case '6': case '7': case '8': case '9':
392			for (width = 0;; ++fmt) {
393				width = width * 10 + ch - '0';
394				ch = *fmt;
395				if (ch < '0' || ch > '9')
396					break;
397			}
398			goto reswitch;
399		case 'l':
400			lflag = 1;
401			goto reswitch;
402		case 'b':
403			ul = va_arg(ap, int);
404			p = va_arg(ap, char *);
405			for (q = ksprintn(ul, *p++, NULL); *q;)
406				putchar(*q--, flags, tp);
407
408			if (!ul)
409				break;
410
411			for (tmp = 0; *p;) {
412				n = *p++;
413				if (ul & (1 << (n - 1))) {
414					putchar(tmp ? ',' : '<', flags, tp);
415					for (; (n = *p) > ' '; ++p)
416						putchar(n, flags, tp);
417					tmp = 1;
418				} else
419					for (; *p > ' '; ++p)
420						continue;
421			}
422			if (tmp)
423				putchar('>', flags, tp);
424			break;
425		case 'c':
426			putchar(va_arg(ap, int), flags, tp);
427			break;
428		case 'r':
429			p = va_arg(ap, char *);
430			kprintf(p, flags, tp, va_arg(ap, va_list));
431			break;
432		case 's':
433			p = va_arg(ap, char *);
434			if (p == NULL)
435				p = "(null)";
436			while (*p)
437				putchar(*p++, flags, tp);
438			break;
439		case 'd':
440			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
441			if ((long)ul < 0) {
442				putchar('-', flags, tp);
443				ul = -(long)ul;
444			}
445			base = 10;
446			goto number;
447		case 'o':
448			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
449			base = 8;
450			goto number;
451		case 'u':
452			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
453			base = 10;
454			goto number;
455		case 'p':
456			ul = (u_long) va_arg(ap, void *);
457			width=8;
458			base=16;
459			putchar('0',flags,tp);
460			putchar('x',flags,tp);
461			goto number;
462		case 'x':
463			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
464			base = 16;
465number:			p = ksprintn(ul, base, &tmp);
466			if (width && (width -= tmp) > 0)
467				while (width--)
468					putchar(padc, flags, tp);
469			while (*p)
470				putchar(*p--, flags, tp);
471			break;
472		default:
473			putchar('%', flags, tp);
474			if (lflag)
475				putchar('l', flags, tp);
476			/* FALLTHROUGH */
477		case '%':
478			putchar(ch, flags, tp);
479		}
480	}
481}
482
483/*
484 * Print a character on console or users terminal.  If destination is
485 * the console then the last MSGBUFS characters are saved in msgbuf for
486 * inspection later.
487 */
488static void
489putchar(c, flags, tp)
490	register int c;
491	int flags;
492	struct tty *tp;
493{
494	extern int msgbufmapped;
495	register struct msgbuf *mbp;
496
497	if (panicstr)
498		constty = NULL;
499	if ((flags & TOCONS) && tp == NULL && constty) {
500		tp = constty;
501		flags |= TOTTY;
502	}
503	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
504	    (flags & TOCONS) && tp == constty)
505		constty = NULL;
506	if ((flags & TOLOG) &&
507	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
508		mbp = msgbufp;
509		if (mbp->msg_magic != MSG_MAGIC) {
510			bzero((caddr_t)mbp, sizeof(*mbp));
511			mbp->msg_magic = MSG_MAGIC;
512		}
513		mbp->msg_bufc[mbp->msg_bufx++] = c;
514		if (mbp->msg_bufx >= MSG_BSIZE)
515			mbp->msg_bufx = 0;
516		if (mbp->msg_bufr == mbp->msg_bufx) {
517			mbp->msg_bufr++;
518			if (mbp->msg_bufr >= MSG_BSIZE)
519				mbp->msg_bufr = 0;
520		}
521	}
522	if ((flags & TOCONS) && constty == NULL && c != '\0')
523		(*v_putc)(c);
524}
525
526/*
527 * Scaled down version of sprintf(3).
528 */
529#ifdef __STDC__
530int
531sprintf(char *buf, const char *cfmt, ...)
532#else
533int
534sprintf(buf, cfmt, va_alist)
535	char *buf, *cfmt;
536#endif
537{
538	register const char *fmt = cfmt;
539	register char *p, *bp;
540	register int ch, base;
541	u_long ul;
542	int lflag;
543	va_list ap;
544
545	va_start(ap, cfmt);
546	for (bp = buf; ; ) {
547		while ((ch = *(u_char *)fmt++) != '%')
548			if ((*bp++ = ch) == '\0')
549				return ((bp - buf) - 1);
550
551		lflag = 0;
552reswitch:	switch (ch = *(u_char *)fmt++) {
553		case 'l':
554			lflag = 1;
555			goto reswitch;
556		case 'c':
557			*bp++ = va_arg(ap, int);
558			break;
559		case 's':
560			p = va_arg(ap, char *);
561			while (*p)
562				*bp++ = *p++;
563			break;
564		case 'd':
565			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
566			if ((long)ul < 0) {
567				*bp++ = '-';
568				ul = -(long)ul;
569			}
570			base = 10;
571			goto number;
572			break;
573		case 'o':
574			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
575			base = 8;
576			goto number;
577			break;
578		case 'u':
579			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
580			base = 10;
581			goto number;
582			break;
583		case 'x':
584			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
585			base = 16;
586number:			for (p = ksprintn(ul, base, NULL); *p;)
587				*bp++ = *p--;
588			break;
589		default:
590			*bp++ = '%';
591			if (lflag)
592				*bp++ = 'l';
593			/* FALLTHROUGH */
594		case '%':
595			*bp++ = ch;
596		}
597	}
598	va_end(ap);
599}
600
601/*
602 * Put a number (base <= 16) in a buffer in reverse order; return an
603 * optional length and a pointer to the NULL terminated (preceded?)
604 * buffer.
605 */
606static char *
607ksprintn(ul, base, lenp)
608	register u_long ul;
609	register int base, *lenp;
610{					/* A long in base 8, plus NULL. */
611	static char buf[sizeof(long) * NBBY / 3 + 2];
612	register char *p;
613
614	p = buf;
615	do {
616		*++p = "0123456789abcdef"[ul % base];
617	} while (ul /= base);
618	if (lenp)
619		*lenp = p - buf;
620	return (p);
621}
622