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