hexdump.c revision 1542
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 */
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/buf.h>
44#include <sys/conf.h>
45#include <sys/reboot.h>
46#include <sys/msgbuf.h>
47#include <sys/proc.h>
48#include <sys/ioctl.h>
49#include <sys/vnode.h>
50#include <sys/file.h>
51#include <sys/tty.h>
52#include <sys/tprintf.h>
53#include <sys/syslog.h>
54#include <sys/malloc.h>
55
56/*
57 * Note that stdarg.h and the ANSI style va_start macro is used for both
58 * ANSI and traditional C compilers.
59 */
60#include <machine/stdarg.h>
61
62#ifdef KADB
63#include <machine/kdbparam.h>
64#endif
65
66#define TOCONS	0x01
67#define TOTTY	0x02
68#define TOLOG	0x04
69
70struct	tty *constty;			/* pointer to console "window" tty */
71
72extern	cnputc();			/* standard console putc */
73int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
74
75void  logpri __P((int level));
76static void  putchar __P((int ch, int flags, struct tty *tp));
77static char *ksprintn __P((u_long num, int base, int *len));
78void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap));
79
80int consintr = 1;			/* Ok to handle console interrupts? */
81
82/*
83 * Variable panicstr contains argument to first call to panic; used as flag
84 * to indicate that the kernel has already called panic.
85 */
86const char *panicstr;
87
88/*
89 * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
90 * and then reboots.  If we are called twice, then we avoid trying to sync
91 * the disks as this often leads to recursive panics.
92 */
93#ifdef __GNUC__
94volatile void boot(int flags);	/* boot() does not return */
95volatile			/* 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	boot(bootopt);
126}
127
128/*
129 * Warn that a system table is full.
130 */
131void
132tablefull(tab)
133	const char *tab;
134{
135
136	log(LOG_ERR, "%s: table is full\n", tab);
137}
138
139/*
140 * Uprintf prints to the controlling terminal for the current process.
141 * It may block if the tty queue is overfull.  No message is printed if
142 * the queue does not clear in a reasonable time.
143 */
144void
145#ifdef __STDC__
146uprintf(const char *fmt, ...)
147#else
148uprintf(fmt, va_alist)
149	char *fmt;
150#endif
151{
152	register struct proc *p = curproc;
153	va_list ap;
154
155	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
156		va_start(ap, fmt);
157		kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
158		va_end(ap);
159	}
160}
161
162tpr_t
163tprintf_open(p)
164	register struct proc *p;
165{
166
167	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
168		SESSHOLD(p->p_session);
169		return ((tpr_t) p->p_session);
170	}
171	return ((tpr_t) NULL);
172}
173
174void
175tprintf_close(sess)
176	tpr_t sess;
177{
178
179	if (sess)
180		SESSRELE((struct session *) sess);
181}
182
183/*
184 * tprintf prints on the controlling terminal associated
185 * with the given session.
186 */
187void
188#ifdef __STDC__
189tprintf(tpr_t tpr, const char *fmt, ...)
190#else
191tprintf(tpr, fmt, va_alist)
192	tpr_t tpr;
193	char *fmt;
194#endif
195{
196	register struct session *sess = (struct session *)tpr;
197	struct tty *tp = NULL;
198	int flags = TOLOG;
199	va_list ap;
200
201	logpri(LOG_INFO);
202	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
203		flags |= TOTTY;
204		tp = sess->s_ttyp;
205	}
206	va_start(ap, fmt);
207	kprintf(fmt, flags, tp, ap);
208	va_end(ap);
209	logwakeup();
210}
211
212/*
213 * Ttyprintf displays a message on a tty; it should be used only by
214 * the tty driver, or anything that knows the underlying tty will not
215 * be revoke(2)'d away.  Other callers should use tprintf.
216 */
217void
218#ifdef __STDC__
219ttyprintf(struct tty *tp, const char *fmt, ...)
220#else
221ttyprintf(tp, fmt, va_alist)
222	struct tty *tp;
223	char *fmt;
224#endif
225{
226	va_list ap;
227
228	va_start(ap, fmt);
229	kprintf(fmt, TOTTY, tp, ap);
230	va_end(ap);
231}
232
233extern	int log_open;
234
235/*
236 * Log writes to the log buffer, and guarantees not to sleep (so can be
237 * called by interrupt routines).  If there is no process reading the
238 * log yet, it writes to the console also.
239 */
240void
241#ifdef __STDC__
242log(int level, const char *fmt, ...)
243#else
244log(level, fmt, va_alist)
245	int level;
246	char *fmt;
247#endif
248{
249	register int s;
250	va_list ap;
251
252	s = splhigh();
253	logpri(level);
254	va_start(ap, fmt);
255	kprintf(fmt, TOLOG, NULL, ap);
256	splx(s);
257	va_end(ap);
258	if (!log_open) {
259		va_start(ap, fmt);
260		kprintf(fmt, TOCONS, NULL, ap);
261		va_end(ap);
262	}
263	logwakeup();
264}
265
266void
267logpri(level)
268	int level;
269{
270	register int ch;
271	register char *p;
272
273	putchar('<', TOLOG, NULL);
274	for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
275		putchar(ch, TOLOG, NULL);
276	putchar('>', TOLOG, NULL);
277}
278
279void
280#ifdef __STDC__
281addlog(const char *fmt, ...)
282#else
283addlog(fmt, va_alist)
284	char *fmt;
285#endif
286{
287	register int s;
288	va_list ap;
289
290	s = splhigh();
291	va_start(ap, fmt);
292	kprintf(fmt, TOLOG, NULL, ap);
293	splx(s);
294	va_end(ap);
295	if (!log_open) {
296		va_start(ap, fmt);
297		kprintf(fmt, TOCONS, NULL, ap);
298		va_end(ap);
299	}
300	logwakeup();
301}
302
303void
304#ifdef __STDC__
305printf(const char *fmt, ...)
306#else
307printf(fmt, va_alist)
308	char *fmt;
309#endif
310{
311	va_list ap;
312	register int savintr;
313
314	savintr = consintr;		/* disable interrupts */
315	consintr = 0;
316	va_start(ap, fmt);
317	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
318	va_end(ap);
319	if (!panicstr)
320		logwakeup();
321	consintr = savintr;		/* reenable interrupts */
322}
323
324/*
325 * Scaled down version of printf(3).
326 *
327 * Two additional formats:
328 *
329 * The format %b is supported to decode error registers.
330 * Its usage is:
331 *
332 *	printf("reg=%b\n", regval, "<base><arg>*");
333 *
334 * where <base> is the output base expressed as a control character, e.g.
335 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
336 * the first of which gives the bit number to be inspected (origin 1), and
337 * the next characters (up to a control character, i.e. a character <= 32),
338 * give the name of the register.  Thus:
339 *
340 *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
341 *
342 * would produce output:
343 *
344 *	reg=3<BITTWO,BITONE>
345 *
346 * The format %r passes an additional format string and argument list
347 * recursively.  Its usage is:
348 *
349 * fn(char *fmt, ...)
350 * {
351 *	va_list ap;
352 *	va_start(ap, fmt);
353 *	printf("prefix: %r: suffix\n", fmt, ap);
354 *	va_end(ap);
355 * }
356 *
357 * Space or zero padding and a field width are supported for the numeric
358 * formats only.
359 */
360void
361kprintf(fmt, flags, tp, ap)
362	register const char *fmt;
363	int flags;
364	struct tty *tp;
365	va_list ap;
366{
367	register char *p, *q;
368	register int ch, n;
369	u_long ul;
370	int base, lflag, tmp, width;
371	char padc;
372
373	for (;;) {
374		padc = ' ';
375		width = 0;
376		while ((ch = *(u_char *)fmt++) != '%') {
377			if (ch == '\0')
378				return;
379			putchar(ch, flags, tp);
380		}
381		lflag = 0;
382reswitch:	switch (ch = *(u_char *)fmt++) {
383		case '0':
384			padc = '0';
385			goto reswitch;
386		case '1': case '2': case '3': case '4':
387		case '5': case '6': case '7': case '8': case '9':
388			for (width = 0;; ++fmt) {
389				width = width * 10 + ch - '0';
390				ch = *fmt;
391				if (ch < '0' || ch > '9')
392					break;
393			}
394			goto reswitch;
395		case 'l':
396			lflag = 1;
397			goto reswitch;
398		case 'b':
399			ul = va_arg(ap, int);
400			p = va_arg(ap, char *);
401			for (q = ksprintn(ul, *p++, NULL); ch = *q--;)
402				putchar(ch, flags, tp);
403
404			if (!ul)
405				break;
406
407			for (tmp = 0; n = *p++;) {
408				if (ul & (1 << (n - 1))) {
409					putchar(tmp ? ',' : '<', flags, tp);
410					for (; (n = *p) > ' '; ++p)
411						putchar(n, flags, tp);
412					tmp = 1;
413				} else
414					for (; *p > ' '; ++p)
415						continue;
416			}
417			if (tmp)
418				putchar('>', flags, tp);
419			break;
420		case 'c':
421			putchar(va_arg(ap, int), flags, tp);
422			break;
423		case 'r':
424			p = va_arg(ap, char *);
425			kprintf(p, flags, tp, va_arg(ap, va_list));
426			break;
427		case 's':
428			p = va_arg(ap, char *);
429			while (ch = *p++)
430				putchar(ch, flags, tp);
431			break;
432		case 'd':
433			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
434			if ((long)ul < 0) {
435				putchar('-', flags, tp);
436				ul = -(long)ul;
437			}
438			base = 10;
439			goto number;
440		case 'o':
441			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
442			base = 8;
443			goto number;
444		case 'u':
445			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
446			base = 10;
447			goto number;
448		case 'x':
449			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
450			base = 16;
451number:			p = ksprintn(ul, base, &tmp);
452			if (width && (width -= tmp) > 0)
453				while (width--)
454					putchar(padc, flags, tp);
455			while (ch = *p--)
456				putchar(ch, flags, tp);
457			break;
458		default:
459			putchar('%', flags, tp);
460			if (lflag)
461				putchar('l', flags, tp);
462			/* FALLTHROUGH */
463		case '%':
464			putchar(ch, flags, tp);
465		}
466	}
467}
468
469/*
470 * Print a character on console or users terminal.  If destination is
471 * the console then the last MSGBUFS characters are saved in msgbuf for
472 * inspection later.
473 */
474static void
475putchar(c, flags, tp)
476	register int c;
477	int flags;
478	struct tty *tp;
479{
480	extern int msgbufmapped;
481	register struct msgbuf *mbp;
482
483	if (panicstr)
484		constty = NULL;
485	if ((flags & TOCONS) && tp == NULL && constty) {
486		tp = constty;
487		flags |= TOTTY;
488	}
489	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
490	    (flags & TOCONS) && tp == constty)
491		constty = NULL;
492	if ((flags & TOLOG) &&
493	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
494		mbp = msgbufp;
495		if (mbp->msg_magic != MSG_MAGIC) {
496			bzero((caddr_t)mbp, sizeof(*mbp));
497			mbp->msg_magic = MSG_MAGIC;
498		}
499		mbp->msg_bufc[mbp->msg_bufx++] = c;
500		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
501			mbp->msg_bufx = 0;
502	}
503	if ((flags & TOCONS) && constty == NULL && c != '\0')
504		(*v_putc)(c);
505}
506
507/*
508 * Scaled down version of sprintf(3).
509 */
510#ifdef __STDC__
511sprintf(char *buf, const char *cfmt, ...)
512#else
513sprintf(buf, cfmt, va_alist)
514	char *buf, *cfmt;
515#endif
516{
517	register const char *fmt = cfmt;
518	register char *p, *bp;
519	register int ch, base;
520	u_long ul;
521	int lflag;
522	va_list ap;
523
524	va_start(ap, cfmt);
525	for (bp = buf; ; ) {
526		while ((ch = *(u_char *)fmt++) != '%')
527			if ((*bp++ = ch) == '\0')
528				return ((bp - buf) - 1);
529
530		lflag = 0;
531reswitch:	switch (ch = *(u_char *)fmt++) {
532		case 'l':
533			lflag = 1;
534			goto reswitch;
535		case 'c':
536			*bp++ = va_arg(ap, int);
537			break;
538		case 's':
539			p = va_arg(ap, char *);
540			while (*bp++ = *p++)
541				continue;
542			--bp;
543			break;
544		case 'd':
545			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
546			if ((long)ul < 0) {
547				*bp++ = '-';
548				ul = -(long)ul;
549			}
550			base = 10;
551			goto number;
552			break;
553		case 'o':
554			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
555			base = 8;
556			goto number;
557			break;
558		case 'u':
559			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
560			base = 10;
561			goto number;
562			break;
563		case 'x':
564			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
565			base = 16;
566number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
567				*bp++ = ch;
568			break;
569		default:
570			*bp++ = '%';
571			if (lflag)
572				*bp++ = 'l';
573			/* FALLTHROUGH */
574		case '%':
575			*bp++ = ch;
576		}
577	}
578	va_end(ap);
579}
580
581/*
582 * Put a number (base <= 16) in a buffer in reverse order; return an
583 * optional length and a pointer to the NULL terminated (preceded?)
584 * buffer.
585 */
586static char *
587ksprintn(ul, base, lenp)
588	register u_long ul;
589	register int base, *lenp;
590{					/* A long in base 8, plus NULL. */
591	static char buf[sizeof(long) * NBBY / 3 + 2];
592	register char *p;
593
594	p = buf;
595	do {
596		*++p = "0123456789abcdef"[ul % base];
597	} while (ul /= base);
598	if (lenp)
599		*lenp = p - buf;
600	return (p);
601}
602