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