1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Computer Consoles Inc. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 char copyright[] = 13 "@(#) Copyright (c) 1988 Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)fsdb.c 5.9 (Berkeley) 02/26/91"; 19 #endif /* not lint */ 20 21 /* 22 * fsdb - file system debugger 23 * 24 * usage: fsdb [options] special 25 * options: 26 * -? display usage 27 * -o override some error conditions 28 * -p"string" set prompt to string 29 * -w open for write 30 */ 31 32 #include <sys/param.h> 33 #include <sys/signal.h> 34 #include <sys/file.h> 35 #include <sys/dir.h> 36 #include <ufs/fs.h> 37 #include <ufs/dinode.h> 38 #include <stdio.h> 39 #include <setjmp.h> 40 #include <paths.h> 41 42 /* 43 * Defines from the 4.3-tahoe file system, for systems with the 4.2 or 4.3 44 * file system. 45 */ 46 #ifndef FS_42POSTBLFMT 47 #define cg_blktot(cgp) (((cgp))->cg_btot) 48 #define cg_blks(fs, cgp, cylno) (((cgp))->cg_b[cylno]) 49 #define cg_inosused(cgp) (((cgp))->cg_iused) 50 #define cg_blksfree(cgp) (((cgp))->cg_free) 51 #define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC) 52 #endif 53 54 /* 55 * Never changing defines. 56 */ 57 #define OCTAL 8 /* octal base */ 58 #define DECIMAL 10 /* decimal base */ 59 #define HEX 16 /* hexadecimal base */ 60 61 /* 62 * Adjustable defines. 63 */ 64 #define NBUF 10 /* number of cache buffers */ 65 #define PROMPTSIZE 80 /* size of user definable prompt */ 66 #define MAXFILES 40000 /* max number of files ls can handle */ 67 #define FIRST_DEPTH 10 /* default depth for find and ls */ 68 #define SECOND_DEPTH 100 /* second try at depth (maximum) */ 69 #define INPUTBUFFER 1040 /* size of input buffer */ 70 #define BYTESPERLINE 16 /* bytes per line of /dxo output */ 71 #define NREG 36 /* number of save registers */ 72 73 /* 74 * Values dependent on sizes of structs and such. 75 */ 76 #define NUMB 3 /* these three are arbitrary, */ 77 #define BLOCK 5 /* but must be different from */ 78 #define FRAGMENT 7 /* the rest (hence odd). */ 79 #define BITSPERCHAR 8 /* couldn't find it anywhere */ 80 #define CHAR (sizeof (char)) 81 #define SHORT (sizeof (short)) 82 #define LONG (sizeof (long)) 83 #define INODE (sizeof (struct dinode)) 84 #define DIRECTORY (sizeof (struct direct)) 85 #define CGRP (sizeof (struct cg)) 86 #define SB (sizeof (struct fs)) 87 #define BLKSIZE (fs->fs_bsize) /* for clarity */ 88 #define FRGSIZE (fs->fs_fsize) 89 #define BLKSHIFT (fs->fs_bshift) 90 #define FRGSHIFT (fs->fs_fshift) 91 92 /* 93 * Messy macros that would otherwise clutter up such glamorous code. 94 */ 95 #define itob(i) ((itod(fs, (i)) << FRGSHIFT) + itoo(fs, (i)) * INODE) 96 #define min(x, y) ((x) < (y) ? (x) : (y)) 97 #define STRINGSIZE(d) ((long)d->d_reclen - \ 98 ((long)&d->d_name[0] - (long)&d->d_ino)) 99 #define letter(c) ((((c) >= 'a')&&((c) <= 'z')) ||\ 100 (((c) >= 'A')&&((c) <= 'Z'))) 101 #define digit(c) (((c) >= '0') && ((c) <= '9')) 102 #define HEXLETTER(c) (((c) >= 'A') && ((c) <= 'F')) 103 #define hexletter(c) (((c) >= 'a') && ((c) <= 'f')) 104 #define octaldigit(c) (((c) >= '0') && ((c) <= '7')) 105 #define uppertolower(c) ((c) - 'A' + 'a') 106 #define hextodigit(c) ((c) - 'a' + 10) 107 #define numtodigit(c) ((c) - '0') 108 #define loword(X) (((ushort *)&X)[1]) 109 #define lobyte(X) (((unsigned char *)&X)[1]) 110 111 /* 112 * buffer cache structure. 113 */ 114 struct buf { 115 struct buf *fwd; 116 struct buf *back; 117 char *blkaddr; 118 short valid; 119 long blkno; 120 } buf[NBUF], bhdr; 121 122 /* 123 * used to hold save registers (see '<' and '>'). 124 */ 125 struct save_registers { 126 long sv_addr; 127 long sv_value; 128 long sv_objsz; 129 } regs[NREG]; 130 131 /* 132 * cd, find, and ls use this to hold filenames. Each filename is broken 133 * up by a slash. In other words, /usr/src/adm would have a len field 134 * of 2 (starting from 0), and filenames->fname[0-2] would hold usr, 135 * src, and adm components of the pathname. 136 */ 137 struct filenames { 138 long ino; /* inode */ 139 long len; /* number of components */ 140 char flag; /* flag if using SECOND_DEPTH allocator */ 141 char find; /* flag if found by find */ 142 char **fname; /* hold components of pathname */ 143 } *filenames, *top; 144 145 struct fs filesystem, *fs; /* super block */ 146 147 /* 148 * Global data. 149 */ 150 char *input_path[MAXPATHLEN]; 151 char *stack_path[MAXPATHLEN]; 152 char *current_path[MAXPATHLEN]; 153 char input_buffer[INPUTBUFFER]; 154 char *prompt; 155 char *buffers; 156 char scratch[64]; 157 char BASE[] = "o u x"; 158 char PROMPT[PROMPTSIZE] = "> "; 159 char laststyle = '/'; 160 char lastpo = 'x'; 161 short input_pointer; 162 short current_pathp; 163 short stack_pathp; 164 short input_pathp; 165 short cmp_level; 166 short nfiles; 167 short type = NUMB; 168 short dirslot; 169 short fd; 170 short c_count; 171 short error; 172 short paren; 173 short trapped; 174 short doing_cd; 175 short doing_find; 176 short find_by_name; 177 short find_by_inode; 178 short long_list; 179 short recursive; 180 short objsz = SHORT; 181 short override = 0; 182 short wrtflag; 183 short base = HEX; 184 short acting_on_inode; 185 short acting_on_directory; 186 short should_print = 1; 187 short clear; 188 short star; 189 long addr; 190 long bod_addr; 191 long value; 192 long erraddr; 193 long errcur_bytes; 194 long errino; 195 long errinum; 196 long cur_cgrp; 197 long cur_ino; 198 long cur_inum; 199 long cur_dir; 200 long cur_block; 201 long cur_bytes; 202 long find_ino; 203 long filesize; 204 long blocksize; 205 long stringsize; 206 long count = 1; 207 long commands; 208 long read_requests; 209 long actual_disk_reads; 210 jmp_buf env; 211 212 extern char *malloc(), *calloc(); 213 char getachar(); 214 char *getblk(), *fmtentry(); 215 void err(); 216 long get(), bmap(), expr(), term(), getnumb(); 217 unsigned long *print_check(); 218 219 /* 220 * main - lines are read up to the unprotected ('\') newline and 221 * held in an input buffer. Characters may be read from the 222 * input buffer using getachar() and unread using ungetachar(). 223 * Reading the whole line ahead allows the use of debuggers 224 * which would otherwise be impossible since the debugger 225 * and fsdb could not share stdin. 226 */ 227 228 main(argc,argv) 229 short argc; 230 char **argv; 231 { 232 233 register char c, *cptr; 234 register short i, j, *iptr; 235 register struct direct *dirp; 236 register struct buf *bp; 237 struct filenames *fn; 238 char *progname; 239 short colon, mode; 240 long temp; 241 unsigned block; 242 int ffcmp(); 243 244 setbuf(stdin, NULL); 245 246 progname = argv[0]; 247 prompt = &PROMPT[0]; 248 /* 249 * Parse options. 250 */ 251 while (argc>1 && argv[1][0] == '-') { 252 if (strcmp("-?", argv[1]) == 0) 253 goto usage; 254 if (strcmp("-o", argv[1]) == 0) { 255 printf("error checking off\n"); 256 override = 1; 257 argc--; argv++; 258 continue; 259 } 260 if (strncmp("-p", argv[1],2) == 0) { 261 prompt = &argv[1][2]; 262 argc--; argv++; 263 continue; 264 } 265 if (strcmp("-w", argv[1]) == 0) { 266 wrtflag = 2; /* suitable for open */ 267 argc--; argv++; 268 continue; 269 } 270 } 271 if (argc!=2) { 272 usage: 273 printf("usage: %s [options] special\n", progname); 274 printf("options:\n"); 275 printf("\t-? display usage\n"); 276 printf("\t-o override some error conditions\n"); 277 printf("\t-p\"string\" set prompt to string\n"); 278 printf("\t-w open for write\n"); 279 exit(1); 280 } 281 /* 282 * Attempt to open the special file. 283 */ 284 if ((fd = open(argv[1],wrtflag)) < 0) { 285 perror(argv[1]); 286 exit(1); 287 } 288 /* 289 * Read in the super block and validate (not too picky). 290 */ 291 if (lseek(fd, SBLOCK * DEV_BSIZE, 0) == -1) { 292 perror(argv[1]); 293 exit(1); 294 } 295 if (read(fd, &filesystem, sizeof filesystem) != sizeof filesystem) { 296 printf("%s: cannot read superblock\n", argv[1]); 297 exit(1); 298 } 299 fs = &filesystem; 300 if (fs->fs_magic != FS_MAGIC) { 301 printf("%s: Bad magic number in file system\n", argv[1]); 302 exit(1); 303 } 304 #ifdef FS_42POSTBLFMT 305 if (fs->fs_postblformat == FS_42POSTBLFMT) 306 fs->fs_nrpos = 8; 307 #endif 308 printf("fsdb of %s %s -- last mounted on %s\n", 309 argv[1], wrtflag ? "(Opened for write)" : "(Read only)", 310 &fs->fs_fsmnt[0]); 311 /* 312 * Malloc buffers and set up cache. 313 */ 314 buffers = malloc(NBUF * BLKSIZE); 315 bhdr.fwd = bhdr.back = &bhdr; 316 for (i=0; i<NBUF; i++) { 317 bp = &buf[i]; 318 bp->blkaddr = buffers + (i * BLKSIZE); 319 bp->valid = 0; 320 insert(bp); 321 } 322 /* 323 * Malloc filenames structure. The space for the actual filenames 324 * is allocated as it needs it. 325 */ 326 filenames = (struct filenames *)calloc(MAXFILES, 327 sizeof (struct filenames)); 328 if (filenames == NULL) { 329 printf("out of memory\n"); 330 exit(1); 331 } 332 333 fn = filenames; 334 335 restore_inode(2); 336 /* 337 * Malloc a few filenames (needed by pwd for example). 338 */ 339 for (i = 0; i < MAXPATHLEN; i++) { 340 input_path[i] = calloc(1, MAXNAMLEN); 341 stack_path[i] = calloc(1, MAXNAMLEN); 342 current_path[i] = calloc(1, MAXNAMLEN); 343 if (current_path[i] == NULL) { 344 printf("out of memory\n"); 345 exit(1); 346 } 347 } 348 current_pathp = -1; 349 350 signal(2,err); 351 setjmp(env); 352 353 getnextinput(); 354 /* 355 * Main loop and case statement. If an error condition occurs 356 * initialization and recovery is attempted. 357 */ 358 for (;;) { 359 if (error) { 360 freemem(filenames, nfiles); 361 nfiles = 0; 362 c_count = 0; 363 count = 1; 364 star = 0; 365 error = 0; 366 paren = 0; 367 acting_on_inode = 0; 368 acting_on_directory = 0; 369 should_print = 1; 370 addr = erraddr; 371 cur_ino = errino; 372 cur_inum = errinum; 373 cur_bytes = errcur_bytes; 374 printf("?\n"); 375 getnextinput(); 376 if (error) 377 continue; 378 } 379 c_count++; 380 381 switch (c = getachar()) { 382 383 case '\n': /* command end */ 384 freemem(filenames, nfiles); 385 nfiles = 0; 386 if (should_print && laststyle == '=') { 387 ungetachar(c); 388 goto calc; 389 } 390 if (c_count == 1) { 391 clear = 0; 392 should_print = 1; 393 erraddr = addr; 394 errino = cur_ino; 395 errinum = cur_inum; 396 errcur_bytes = cur_bytes; 397 switch (objsz) { 398 case DIRECTORY: 399 if ((addr = 400 getdirslot(dirslot+1)) == 0) 401 should_print = 0; 402 if (error) { 403 ungetachar(c); 404 continue; 405 } 406 break; 407 case INODE: 408 cur_inum++; 409 addr = itob(cur_inum); 410 if (!icheck(addr)) { 411 cur_inum--; 412 should_print = 0; 413 } 414 break; 415 case CGRP: 416 case SB: 417 cur_cgrp++; 418 if ((addr=cgrp_check(cur_cgrp)) == 0) { 419 cur_cgrp--; 420 continue; 421 } 422 break; 423 default: 424 addr += objsz; 425 cur_bytes += objsz; 426 if (valid_addr() == 0) 427 continue; 428 } 429 } 430 if (type == NUMB) 431 trapped = 0; 432 if (should_print) 433 switch (objsz) { 434 case DIRECTORY: 435 fprnt('?', 'd'); 436 break; 437 case INODE: 438 fprnt('?', 'i'); 439 if (!error) 440 cur_ino = addr; 441 break; 442 case CGRP: 443 fprnt('?', 'c'); 444 break; 445 case SB: 446 fprnt('?', 's'); 447 break; 448 case CHAR: 449 case SHORT: 450 case LONG: 451 fprnt(laststyle, lastpo); 452 } 453 if (error) { 454 ungetachar(c); 455 continue; 456 } 457 c_count = colon = acting_on_inode = 0; 458 acting_on_directory = 0; 459 should_print = 1; 460 getnextinput(); 461 if (error) 462 continue; 463 erraddr = addr; 464 errino = cur_ino; 465 errinum = cur_inum; 466 errcur_bytes = cur_bytes; 467 continue; 468 469 case '(': /* numeric expression or unknown command */ 470 default: 471 colon = 0; 472 if (digit(c) || c == '(') { 473 ungetachar(c); 474 addr = expr(); 475 type = NUMB; 476 value = addr; 477 continue; 478 } 479 printf("unknown command or bad syntax\n"); 480 error++; 481 continue; 482 483 case '?': /* general print facilities */ 484 case '/': 485 fprnt(c, getachar()); 486 continue; 487 488 case ';': /* command separator and . */ 489 case '\t': 490 case ' ': 491 case '.': 492 continue; 493 494 case ':': /* command indicator */ 495 colon++; 496 commands++; 497 should_print = 0; 498 stringsize = 0; 499 trapped = 0; 500 continue; 501 502 case ',': /* count indicator */ 503 colon = star = 0; 504 if ((c = getachar()) == '*') { 505 star = 1; 506 count = BLKSIZE; 507 } else { 508 ungetachar(c); 509 count = expr(); 510 if (error) 511 continue; 512 if (!count) 513 count = 1; 514 } 515 clear = 0; 516 continue; 517 518 case '+': /* address addition */ 519 colon = 0; 520 c = getachar(); 521 ungetachar(c); 522 if (c == '\n') 523 temp = 1; 524 else { 525 temp = expr(); 526 if (error) 527 continue; 528 } 529 erraddr = addr; 530 errcur_bytes = cur_bytes; 531 switch (objsz) { 532 case DIRECTORY: 533 addr = getdirslot(dirslot + temp); 534 if (error) 535 continue; 536 break; 537 case INODE: 538 cur_inum += temp; 539 addr = itob(cur_inum); 540 if (!icheck(addr)) { 541 cur_inum -= temp; 542 continue; 543 } 544 break; 545 case CGRP: 546 case SB: 547 cur_cgrp += temp; 548 if ((addr = cgrp_check(cur_cgrp)) == 0) { 549 cur_cgrp -= temp; 550 continue; 551 } 552 break; 553 default: 554 laststyle = '/'; 555 addr += temp * objsz; 556 cur_bytes += temp * objsz; 557 if (valid_addr() == 0) 558 continue; 559 } 560 value = get(objsz); 561 continue; 562 563 case '-': /* address subtraction */ 564 colon = 0; 565 c = getachar(); 566 ungetachar(c); 567 if (c == '\n') 568 temp = 1; 569 else { 570 temp = expr(); 571 if (error) 572 continue; 573 } 574 erraddr = addr; 575 errcur_bytes = cur_bytes; 576 switch (objsz) { 577 case DIRECTORY: 578 addr = getdirslot(dirslot - temp); 579 if (error) 580 continue; 581 break; 582 case INODE: 583 cur_inum -= temp; 584 addr = itob(cur_inum); 585 if (!icheck(addr)) { 586 cur_inum += temp; 587 continue; 588 } 589 break; 590 case CGRP: 591 case SB: 592 cur_cgrp -= temp; 593 if ((addr = cgrp_check(cur_cgrp)) == 0) { 594 cur_cgrp += temp; 595 continue; 596 } 597 break; 598 default: 599 laststyle = '/'; 600 addr -= temp * objsz; 601 cur_bytes -= temp * objsz; 602 if (valid_addr() == 0) 603 continue; 604 } 605 value = get(objsz); 606 continue; 607 608 case '*': /* address multiplication */ 609 colon = 0; 610 temp = expr(); 611 if (error) 612 continue; 613 if (objsz != INODE && objsz != DIRECTORY) 614 laststyle = '/'; 615 addr *= temp; 616 value = get(objsz); 617 continue; 618 619 case '%': /* address division */ 620 colon = 0; 621 temp = expr(); 622 if (error) 623 continue; 624 if (!temp) { 625 printf("divide by zero\n"); 626 error++; 627 continue; 628 } 629 if (objsz != INODE && objsz != DIRECTORY) 630 laststyle = '/'; 631 addr /= temp; 632 value = get(objsz); 633 continue; 634 635 case '=': { /* assignment operation */ 636 short tbase = base; 637 638 calc: 639 c = getachar(); 640 if (c == '\n') { 641 ungetachar(c); 642 c = lastpo; 643 if (acting_on_inode == 1) { 644 if (c != 'o' && c != 'd' && c != 'x' && 645 c != 'O' && c != 'D' && c != 'X') { 646 switch (objsz) { 647 case LONG: 648 c = lastpo = 'X'; 649 break; 650 case SHORT: 651 c = lastpo = 'x'; 652 break; 653 case CHAR: 654 c = lastpo = 'c'; 655 } 656 } 657 } else { 658 if (acting_on_inode == 2) 659 c = lastpo = 't'; 660 } 661 } else if (acting_on_inode) 662 lastpo = c; 663 should_print = star = 0; 664 count = 1; 665 erraddr = addr; 666 errcur_bytes = cur_bytes; 667 switch (c) { 668 case '"': /* character string */ 669 if (type == NUMB) { 670 blocksize = BLKSIZE; 671 filesize = BLKSIZE * 2; 672 cur_bytes = blkoff(fs, addr); 673 if (objsz==DIRECTORY || objsz==INODE) 674 lastpo = 'X'; 675 } 676 puta(); 677 continue; 678 case '+': /* =+ operator */ 679 temp = expr(); 680 value = get(objsz); 681 if (!error) 682 put(value+temp,objsz); 683 continue; 684 case '-': /* =- operator */ 685 temp = expr(); 686 value = get(objsz); 687 if (!error) 688 put(value-temp,objsz); 689 continue; 690 case 'b': 691 case 'c': 692 if (objsz == CGRP) 693 fprnt('?', c); 694 else 695 fprnt('/', c); 696 continue; 697 case 'i': 698 addr = cur_ino; 699 fprnt('?', 'i'); 700 continue; 701 case 's': 702 fprnt('?', 's'); 703 continue; 704 case 't': 705 case 'T': 706 laststyle = '='; 707 printf("\t\t"); 708 printf("%s", ctime(&value)); 709 continue; 710 case 'o': 711 base = OCTAL; 712 goto otx; 713 case 'd': 714 if (objsz == DIRECTORY) { 715 addr = cur_dir; 716 fprnt('?', 'd'); 717 continue; 718 } 719 base = DECIMAL; 720 goto otx; 721 case 'x': 722 base = HEX; 723 otx: 724 laststyle = '='; 725 printf("\t\t"); 726 if (acting_on_inode) 727 print(value & 0177777L, 12, -8, 0); 728 else 729 print(addr & 0177777L, 12, -8, 0); 730 printf("\n"); 731 base = tbase; 732 continue; 733 case 'O': 734 base = OCTAL; 735 goto OTX; 736 case 'D': 737 base = DECIMAL; 738 goto OTX; 739 case 'X': 740 base = HEX; 741 OTX: 742 laststyle = '='; 743 printf("\t\t"); 744 if (acting_on_inode) 745 print(value, 12, -8, 0); 746 else 747 print(addr, 12, -8, 0); 748 printf("\n"); 749 base = tbase; 750 continue; 751 default: /* regular assignment */ 752 ungetachar(c); 753 value = expr(); 754 if (error) 755 printf("syntax error\n"); 756 else 757 put(value,objsz); 758 continue; 759 } 760 } 761 762 case '>': /* save current address */ 763 colon = 0; 764 should_print = 0; 765 c = getachar(); 766 if (!letter(c) && !digit(c)) { 767 printf("invalid register specification, "); 768 printf("must be letter or digit\n"); 769 error++; 770 continue; 771 } 772 if (letter(c)) { 773 if (c < 'a') 774 c = uppertolower(c); 775 c = hextodigit(c); 776 } else 777 c = numtodigit(c); 778 regs[c].sv_addr = addr; 779 regs[c].sv_value = value; 780 regs[c].sv_objsz = objsz; 781 continue; 782 783 case '<': /* restore saved address */ 784 colon = 0; 785 should_print = 0; 786 c = getachar(); 787 if (!letter(c) && !digit(c)) { 788 printf("invalid register specification, "); 789 printf("must be letter or digit\n"); 790 error++; 791 continue; 792 } 793 if (letter(c)) { 794 if (c < 'a') 795 c = uppertolower(c); 796 c = hextodigit(c); 797 } else 798 c = numtodigit(c); 799 addr = regs[c].sv_addr; 800 value = regs[c].sv_value; 801 objsz = regs[c].sv_objsz; 802 continue; 803 804 case 'a': 805 if (colon) 806 colon = 0; 807 else 808 goto no_colon; 809 if (match("at", 2)) { /* access time */ 810 acting_on_inode = 2; 811 should_print = 1; 812 addr = (long) 813 &((struct dinode *)cur_ino)->di_atime; 814 value = get(LONG); 815 type = NULL; 816 continue; 817 } 818 goto bad_syntax; 819 820 case 'b': 821 if (colon) 822 colon = 0; 823 else 824 goto no_colon; 825 if (match("block", 2)) { /* block conversion */ 826 if (type == NUMB) { 827 value = addr; 828 cur_bytes = 0; 829 blocksize = BLKSIZE; 830 filesize = BLKSIZE * 2; 831 } 832 addr = value << FRGSHIFT; 833 bod_addr = addr; 834 value = get(LONG); 835 type = BLOCK; 836 dirslot = 0; 837 trapped++; 838 continue; 839 } 840 if (match("bs", 2)) { /* block size */ 841 acting_on_inode = 1; 842 should_print = 1; 843 if (icheck(cur_ino) == 0) 844 continue; 845 addr = (long) 846 &((struct dinode *)cur_ino)->di_blocks; 847 value = get(LONG); 848 type = NULL; 849 continue; 850 } 851 if (match("base", 2)) { /* change/show base */ 852 showbase: 853 if ((c = getachar()) == '\n') { 854 ungetachar(c); 855 printf("base =\t\t"); 856 switch (base) { 857 case OCTAL: 858 printf("OCTAL\n"); 859 continue; 860 case DECIMAL: 861 printf("DECIMAL\n"); 862 continue; 863 case HEX: 864 printf("HEX\n"); 865 continue; 866 } 867 } 868 if (c != '=') { 869 printf("missing '='\n"); 870 error++; 871 continue; 872 } 873 value = expr(); 874 switch (value) { 875 default: 876 printf("invalid base\n"); 877 error++; 878 break; 879 case OCTAL: 880 case DECIMAL: 881 case HEX: 882 base = value; 883 } 884 goto showbase; 885 } 886 goto bad_syntax; 887 888 case 'c': 889 if (colon) 890 colon = 0; 891 else 892 goto no_colon; 893 if (match("cd", 2)) { /* change directory */ 894 top = filenames - 1; 895 eat_spaces(); 896 if ((c = getachar()) == '\n') { 897 ungetachar(c); 898 current_pathp = -1; 899 restore_inode(2); 900 continue; 901 } 902 ungetachar(c); 903 temp = cur_inum; 904 doing_cd = 1; 905 parse(); 906 doing_cd = 0; 907 if (nfiles != 1) { 908 restore_inode(temp); 909 if (!error) { 910 print_path(input_path, 911 input_pathp); 912 if (nfiles == 0) 913 printf(" not found\n"); 914 else 915 printf(" ambiguous\n"); 916 error++; 917 } 918 continue; 919 } 920 restore_inode(filenames->ino); 921 if ((mode = icheck(addr)) == 0) 922 continue; 923 if ((mode & IFMT) != IFDIR) { 924 restore_inode(temp); 925 print_path(input_path, input_pathp); 926 printf(" not a directory\n"); 927 error++; 928 continue; 929 } 930 for (i = 0; i <= top->len; i++) 931 strcpy(current_path[i], 932 top->fname[i]); 933 current_pathp = top->len; 934 continue; 935 } 936 if (match("cg", 2)) { /* cylinder group */ 937 if (type == NUMB) 938 value = addr; 939 if (value > fs->fs_ncg - 1) { 940 printf("maximum cylinder group is "); 941 print(fs->fs_ncg - 1, 8, -8, 0); 942 printf("\n"); 943 error++; 944 continue; 945 } 946 type = objsz = CGRP; 947 cur_cgrp = value; 948 addr = cgtod(fs, cur_cgrp) << FRGSHIFT; 949 continue; 950 } 951 if (match("ct", 2)) { /* creation time */ 952 acting_on_inode = 2; 953 should_print = 1; 954 addr = (long) 955 &((struct dinode *)cur_ino)->di_ctime; 956 value = get(LONG); 957 type = NULL; 958 continue; 959 } 960 goto bad_syntax; 961 962 case 'd': 963 if (colon) 964 colon = 0; 965 else 966 goto no_colon; 967 if (match("directory", 2)) { /* directory offsets */ 968 if (type == NUMB) 969 value = addr; 970 objsz = DIRECTORY; 971 type = DIRECTORY; 972 addr = getdirslot(value); 973 continue; 974 } 975 if (match("db", 2)) { /* direct block */ 976 acting_on_inode = 1; 977 should_print = 1; 978 if (type == NUMB) 979 value = addr; 980 if (value >= NDADDR) { 981 printf("direct blocks are 0 to "); 982 print(NDADDR - 1, 0, 0, 0); 983 printf("\n"); 984 error++; 985 continue; 986 } 987 addr = cur_ino; 988 if (!icheck(addr)) 989 continue; 990 addr = (long) 991 &((struct dinode *)cur_ino)->di_db[value]; 992 bod_addr = addr; 993 cur_bytes = (value) * BLKSIZE; 994 cur_block = value; 995 type = BLOCK; 996 dirslot = 0; 997 value = get(LONG); 998 if (!value && !override) { 999 printf("non existent block\n"); 1000 error++; 1001 } 1002 continue; 1003 } 1004 goto bad_syntax; 1005 1006 case 'f': 1007 if (colon) 1008 colon = 0; 1009 else 1010 goto no_colon; 1011 if (match("find", 3)) { /* find command */ 1012 find(); 1013 continue; 1014 } 1015 if (match("fragment", 2)) { /* fragment conv. */ 1016 if (type == NUMB) { 1017 value = addr; 1018 cur_bytes = 0; 1019 blocksize = FRGSIZE; 1020 filesize = FRGSIZE * 2; 1021 } 1022 if (min(blocksize, filesize) - cur_bytes > 1023 FRGSIZE) { 1024 blocksize = cur_bytes + FRGSIZE; 1025 filesize = blocksize * 2; 1026 } 1027 addr = value << FRGSHIFT; 1028 bod_addr = addr; 1029 value = get(LONG); 1030 type = FRAGMENT; 1031 dirslot = 0; 1032 trapped++; 1033 continue; 1034 } 1035 if (match("file", 4)) { /* access as file */ 1036 acting_on_inode = 1; 1037 should_print = 1; 1038 if (type == NUMB) 1039 value = addr; 1040 addr = cur_ino; 1041 if ((mode = icheck(addr)) == 0) 1042 continue; 1043 if ((mode & IFCHR) && !override) { 1044 printf("special device\n"); 1045 error++; 1046 continue; 1047 } 1048 if ((addr = (bmap(value) << FRGSHIFT)) == 0) 1049 continue; 1050 cur_block = value; 1051 bod_addr = addr; 1052 type = BLOCK; 1053 dirslot = 0; 1054 continue; 1055 } 1056 if (match("fill", 4)) { /* fill */ 1057 if (getachar() != '=') { 1058 printf("missing '='\n"); 1059 error++; 1060 continue; 1061 } 1062 if (objsz == INODE || objsz == DIRECTORY) { 1063 printf("can't fill inode or directory\n"); 1064 error++; 1065 continue; 1066 } 1067 fill(); 1068 continue; 1069 } 1070 goto bad_syntax; 1071 1072 case 'g': 1073 if (colon) 1074 colon = 0; 1075 else 1076 goto no_colon; 1077 if (match("gid", 1)) { /* group id */ 1078 acting_on_inode = 1; 1079 should_print = 1; 1080 addr = (long) 1081 &((struct dinode *)cur_ino)->di_gid; 1082 value = get(SHORT); 1083 type = NULL; 1084 continue; 1085 } 1086 goto bad_syntax; 1087 1088 case 'i': 1089 if (colon) 1090 colon = 0; 1091 else 1092 goto no_colon; 1093 if (match("inode", 2)) { /* i# to inode conversion */ 1094 if (c_count == 2) { 1095 addr = cur_ino; 1096 value = get(INODE); 1097 type = NULL; 1098 laststyle = '='; 1099 lastpo = 'i'; 1100 should_print = 1; 1101 continue; 1102 } 1103 if (type == NUMB) 1104 value = addr; 1105 addr = itob(value); 1106 if (!icheck(addr)) 1107 continue; 1108 cur_ino = addr; 1109 cur_inum = value; 1110 value = get(INODE); 1111 type = NULL; 1112 continue; 1113 } 1114 if (match("ib", 2)) { /* indirect block */ 1115 acting_on_inode = 1; 1116 should_print = 1; 1117 if (type == NUMB) 1118 value = addr; 1119 if (value >= NIADDR) { 1120 printf("indirect blocks are 0 to "); 1121 print(NIADDR - 1, 0, 0, 0); 1122 printf("\n"); 1123 error++; 1124 continue; 1125 } 1126 addr = (long) 1127 &((struct dinode *)cur_ino)->di_ib[value]; 1128 cur_bytes = (NDADDR - 1) * BLKSIZE; 1129 temp = 1; 1130 for (i = 0; i < value; i++) { 1131 temp *= NINDIR(fs) * BLKSIZE; 1132 cur_bytes += temp; 1133 } 1134 type = BLOCK; 1135 dirslot = 0; 1136 value = get(LONG); 1137 if (!value && !override) { 1138 printf("non existent block\n"); 1139 error++; 1140 } 1141 continue; 1142 } 1143 goto bad_syntax; 1144 1145 case 'l': 1146 if (colon) 1147 colon = 0; 1148 else 1149 goto no_colon; 1150 if (match("ls", 2)) { /* ls command */ 1151 temp = cur_inum; 1152 recursive = long_list = 0; 1153 top = filenames - 1; 1154 for (;;) { 1155 eat_spaces(); 1156 if ((c = getachar()) == '-') { 1157 if ((c = getachar()) == 'R') { 1158 recursive = 1; 1159 continue; 1160 } else if (c == 'l') { 1161 long_list = 1; 1162 } else { 1163 printf("unknown option "); 1164 printf("'%c'\n", c); 1165 error++; 1166 break; 1167 } 1168 } else 1169 ungetachar(c); 1170 if ((c = getachar()) == '\n') { 1171 if (c_count != 2) { 1172 ungetachar(c); 1173 break; 1174 } 1175 } 1176 c_count++; 1177 ungetachar(c); 1178 parse(); 1179 restore_inode(temp); 1180 if (error) 1181 break; 1182 } 1183 recursive = 0; 1184 if (error || nfiles == 0) { 1185 if (!error) { 1186 print_path(input_path, 1187 input_pathp); 1188 printf(" not found\n"); 1189 } 1190 continue; 1191 } 1192 if (nfiles) { 1193 cmp_level = 0; 1194 qsort((char *)filenames, nfiles, 1195 sizeof (struct filenames), ffcmp); 1196 ls(filenames, filenames + (nfiles - 1), 0); 1197 } else { 1198 printf("no match\n"); 1199 error++; 1200 } 1201 restore_inode(temp); 1202 continue; 1203 } 1204 if (match("ln", 2)) { /* link count */ 1205 acting_on_inode = 1; 1206 should_print = 1; 1207 addr = (long) 1208 &((struct dinode *)cur_ino)->di_nlink; 1209 value = get(SHORT); 1210 type = NULL; 1211 continue; 1212 } 1213 goto bad_syntax; 1214 1215 case 'm': 1216 if (colon) 1217 colon = 0; 1218 else 1219 goto no_colon; 1220 addr = cur_ino; 1221 if ((mode = icheck(addr)) == 0) 1222 continue; 1223 if (match("mt", 2)) { /* modification time */ 1224 acting_on_inode = 2; 1225 should_print = 1; 1226 addr = (long) 1227 &((struct dinode *)cur_ino)->di_mtime; 1228 value = get(LONG); 1229 type = NULL; 1230 continue; 1231 } 1232 if (match("md", 2)) { /* mode */ 1233 acting_on_inode = 1; 1234 should_print = 1; 1235 addr = (long) 1236 &((struct dinode *)cur_ino)->di_mode; 1237 value = get(SHORT); 1238 type = NULL; 1239 continue; 1240 } 1241 if (match("maj", 2)) { /* major device number */ 1242 acting_on_inode = 1; 1243 should_print = 1; 1244 if (devcheck(mode)) 1245 continue; 1246 addr = (long) 1247 &((struct dinode *)cur_ino)->di_db[1]; 1248 value = get(LONG); 1249 type = NULL; 1250 continue; 1251 } 1252 if (match("min", 2)) { /* minor device number */ 1253 acting_on_inode = 1; 1254 should_print = 1; 1255 if (devcheck(mode)) 1256 continue; 1257 addr = (long) 1258 &((struct dinode *)cur_ino)->di_db[0]; 1259 value = get(LONG); 1260 type = NULL; 1261 continue; 1262 } 1263 goto bad_syntax; 1264 1265 case 'n': 1266 if (colon) 1267 colon = 0; 1268 else 1269 goto no_colon; 1270 if (match("nm", 1)) { /* directory name */ 1271 objsz = DIRECTORY; 1272 acting_on_directory = 1; 1273 cur_dir = addr; 1274 if ((cptr = getblk(addr)) == 0) 1275 continue; 1276 dirp = (struct direct *)(cptr+blkoff(fs, addr)); 1277 stringsize = (long)dirp->d_reclen - 1278 ((long)&dirp->d_name[0] - (long)&dirp->d_ino); 1279 addr = (long) 1280 &((struct direct *)addr)->d_name[0]; 1281 type = NULL; 1282 continue; 1283 } 1284 goto bad_syntax; 1285 1286 case 'o': 1287 if (colon) 1288 colon = 0; 1289 else 1290 goto no_colon; 1291 if (match("override", 1)) { /* override flip flop */ 1292 if (override = !override) 1293 printf("error checking off\n"); 1294 else 1295 printf("error checking on\n"); 1296 continue; 1297 } 1298 goto bad_syntax; 1299 1300 case 'p': 1301 if (colon) 1302 colon = 0; 1303 else 1304 goto no_colon; 1305 if (match("pwd", 2)) { /* print working dir */ 1306 print_path(current_path, current_pathp); 1307 printf("\n"); 1308 continue; 1309 } 1310 if (match("prompt", 2)) { /* change prompt */ 1311 if ((c = getachar()) != '=') { 1312 printf("missing '='\n"); 1313 error++; 1314 continue; 1315 } 1316 if ((c = getachar()) != '"') { 1317 printf("missing '\"'\n"); 1318 error++; 1319 continue; 1320 } 1321 i = 0; 1322 prompt = &prompt[0]; 1323 while ((c = getachar()) != '"' && 1324 c != '\n') { 1325 prompt[i++] = c; 1326 if (i >= PROMPTSIZE) { 1327 printf("string too long\n"); 1328 error++; 1329 break; 1330 } 1331 } 1332 prompt[i] = '\0'; 1333 continue; 1334 } 1335 goto bad_syntax; 1336 1337 case 'q': 1338 if (!colon) 1339 goto no_colon; 1340 if (match("quit", 1)) { /* quit */ 1341 if ((c = getachar()) != '\n') { 1342 error++; 1343 continue; 1344 } 1345 exit(0); 1346 } 1347 goto bad_syntax; 1348 1349 case 's': 1350 if (colon) 1351 colon = 0; 1352 else 1353 goto no_colon; 1354 if (match("sb", 2)) { /* super block */ 1355 if (c_count == 2) { 1356 cur_cgrp = -1; 1357 type = objsz = SB; 1358 laststyle = '='; 1359 lastpo = 's'; 1360 should_print = 1; 1361 continue; 1362 } 1363 if (type == NUMB) 1364 value = addr; 1365 if (value > fs->fs_ncg - 1) { 1366 printf("maximum super block is "); 1367 print(fs->fs_ncg - 1, 8, -8, 0); 1368 printf("\n"); 1369 error++; 1370 continue; 1371 } 1372 type = objsz = SB; 1373 cur_cgrp = value; 1374 addr = cgsblock(fs, cur_cgrp) << FRGSHIFT; 1375 continue; 1376 } 1377 if (match("sz", 2)) { /* file size */ 1378 acting_on_inode = 1; 1379 should_print = 1; 1380 addr = (long) 1381 &((struct dinode *)cur_ino)->di_size; 1382 value = get(LONG); 1383 type = NULL; 1384 continue; 1385 } 1386 goto bad_syntax; 1387 1388 case 'u': 1389 if (colon) 1390 colon = 0; 1391 else 1392 goto no_colon; 1393 if (match("uid", 1)) { /* user id */ 1394 acting_on_inode = 1; 1395 should_print = 1; 1396 addr = (long) 1397 &((struct dinode *)cur_ino)->di_uid; 1398 value = get(SHORT); 1399 type = NULL; 1400 continue; 1401 } 1402 goto bad_syntax; 1403 1404 case 'F': /* buffer status (internal use only) */ 1405 if (colon) 1406 colon = 0; 1407 else 1408 goto no_colon; 1409 for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd) 1410 printf("%8x %d\n",bp->blkno,bp->valid); 1411 printf("\n"); 1412 printf("# commands\t\t%d\n", commands); 1413 printf("# read requests\t\t%d\n", read_requests); 1414 printf("# actual disk reads\t%d\n", actual_disk_reads); 1415 continue; 1416 no_colon: 1417 printf("a colon should precede a command\n"); 1418 error++; 1419 continue; 1420 bad_syntax: 1421 printf("more letters needed to distinguish command\n"); 1422 error++; 1423 continue; 1424 } 1425 } 1426 } 1427 1428 /* 1429 * getachar - get next character from input buffer. 1430 */ 1431 char 1432 getachar() 1433 { 1434 return(input_buffer[input_pointer++]); 1435 } 1436 1437 /* 1438 * ungetachar - return character to input buffer. 1439 */ 1440 ungetachar(c) 1441 register char c; 1442 { 1443 if (input_pointer == 0) { 1444 printf("internal problem maintaining input buffer\n"); 1445 error++; 1446 return; 1447 } 1448 input_buffer[--input_pointer] = c; 1449 } 1450 1451 /* 1452 * getnextinput - display the prompt and read an input line. 1453 * An input line is up to 128 characters terminated by the newline 1454 * character. Handle overflow, shell escape, and eof. 1455 */ 1456 getnextinput() 1457 { 1458 register int i; 1459 register char c; 1460 register short pid, rpid; 1461 int retcode; 1462 1463 newline: 1464 i = 0; 1465 printf("%s", prompt); 1466 ignore_eol: 1467 while ((c = getc(stdin)) != '\n' && !(c == '!' && i == 0) && 1468 !feof(stdin) && i <= INPUTBUFFER - 2) 1469 input_buffer[i++] = c; 1470 if (input_buffer[i - 1] == '\\') { 1471 input_buffer[i++] = c; 1472 goto ignore_eol; 1473 } 1474 if (feof(stdin)) { 1475 printf("\n"); 1476 exit(0); 1477 } 1478 if (c == '!') { 1479 if ((pid = fork()) == 0) { 1480 execl(_PATH_BSHELL, "sh", "-t", 0); 1481 error++; 1482 return; 1483 } 1484 while ((rpid = wait(&retcode)) != pid && rpid != -1) 1485 ; 1486 printf("!\n"); 1487 goto newline; 1488 } 1489 if (c != '\n') 1490 printf("input truncated to 128 characters\n"); 1491 input_buffer[i] = '\n'; 1492 input_pointer = 0; 1493 } 1494 1495 /* 1496 * eat_spaces - read extraneous spaces. 1497 */ 1498 eat_spaces() 1499 { 1500 register char c; 1501 1502 while ((c = getachar()) == ' ') 1503 ; 1504 ungetachar(c); 1505 } 1506 1507 /* 1508 * restore_inode - set up all inode indicators so inum is now 1509 * the current inode. 1510 */ 1511 restore_inode(inum) 1512 long inum; 1513 { 1514 errinum = cur_inum = inum; 1515 addr = errino = cur_ino = itob(inum); 1516 } 1517 1518 /* 1519 * match - return false if the input does not match string up to 1520 * upto letters. Then proceed to chew up extraneous letters. 1521 */ 1522 match(string, upto) 1523 register char *string; 1524 register int upto; 1525 { 1526 register int i, length = strlen(string) - 1; 1527 register char c; 1528 int save_upto = upto; 1529 1530 while (--upto) { 1531 string++; 1532 if ((c = getachar()) != *string) { 1533 for (i = save_upto - upto; i; i--) { 1534 ungetachar(c); 1535 c = *--string; 1536 } 1537 return(0); 1538 } 1539 length--; 1540 } 1541 while (length--) { 1542 string++; 1543 if ((c = getachar()) != *string) { 1544 ungetachar(c); 1545 return(1); 1546 } 1547 } 1548 return(1); 1549 } 1550 1551 /* 1552 * expr - expression evaluator. Will evaluate expressions from 1553 * left to right with no operator precedence. Parentheses may 1554 * be used. 1555 */ 1556 long 1557 expr() 1558 { 1559 register long numb = 0, temp; 1560 register char c; 1561 1562 numb = term(); 1563 for (;;) { 1564 if (error) 1565 return; 1566 c = getachar(); 1567 switch (c) { 1568 1569 case '+': 1570 numb += term(); 1571 continue; 1572 1573 case '-': 1574 numb -= term(); 1575 continue; 1576 1577 case '*': 1578 numb *= term(); 1579 continue; 1580 1581 case '%': 1582 temp = term(); 1583 if (!temp) { 1584 printf("divide by zero\n"); 1585 error++; 1586 return; 1587 } 1588 numb /= temp; 1589 continue; 1590 1591 case ')': 1592 paren--; 1593 return(numb); 1594 1595 default: 1596 ungetachar(c); 1597 if (paren && !error) { 1598 printf("missing ')'\n"); 1599 error++; 1600 } 1601 return(numb); 1602 } 1603 } 1604 } 1605 1606 /* 1607 * term - used by expression evaluator to get an operand. 1608 */ 1609 long 1610 term() 1611 { 1612 register char c; 1613 1614 switch (c = getachar()) { 1615 1616 default: 1617 ungetachar(c); 1618 1619 case '+': 1620 return(getnumb()); 1621 1622 case '-': 1623 return(-getnumb()); 1624 1625 case '(': 1626 paren++; 1627 return(expr()); 1628 } 1629 } 1630 1631 /* 1632 * getnumb - read a number from the input stream. A leading 1633 * zero signifies octal interpretation, a leading '0x' 1634 * signifies hexadecimal, and a leading '0t' signifies 1635 * decimal. If the first character is a character, 1636 * return an error. 1637 */ 1638 long 1639 getnumb() 1640 { 1641 1642 register char c, savec; 1643 long number = 0, tbase, num; 1644 extern short error; 1645 1646 c = getachar(); 1647 if (!digit(c)) { 1648 error++; 1649 ungetachar(c); 1650 return(-1); 1651 } 1652 if (c == '0') { 1653 tbase = OCTAL; 1654 if ((c = getachar()) == 'x') 1655 tbase = HEX; 1656 else if (c == 't') 1657 tbase = DECIMAL; 1658 else ungetachar(c); 1659 } else { 1660 tbase = base; 1661 ungetachar(c); 1662 } 1663 for (;;) { 1664 num = tbase; 1665 c = savec = getachar(); 1666 if (HEXLETTER(c)) 1667 c = uppertolower(c); 1668 switch (tbase) { 1669 case HEX: 1670 if (hexletter(c)) { 1671 num = hextodigit(c); 1672 break; 1673 } 1674 case DECIMAL: 1675 if (digit(c)) 1676 num = numtodigit(c); 1677 break; 1678 case OCTAL: 1679 if (octaldigit(c)) 1680 num = numtodigit(c); 1681 } 1682 if (num == tbase) 1683 break; 1684 number = number * tbase + num; 1685 } 1686 ungetachar(savec); 1687 return(number); 1688 } 1689 1690 /* 1691 * find - the syntax is almost identical to the unix command. 1692 * find dir [-name pattern] [-inum number] 1693 * Note: only one of -name or -inum may be used at a time. 1694 * Also, the -print is not needed (implied). 1695 */ 1696 find() 1697 { 1698 register struct filenames *fn; 1699 register char c; 1700 long temp; 1701 short mode; 1702 1703 eat_spaces(); 1704 temp = cur_inum; 1705 top = filenames - 1; 1706 doing_cd = 1; 1707 parse(); 1708 doing_cd = 0; 1709 if (nfiles != 1) { 1710 restore_inode(temp); 1711 if (!error) { 1712 print_path(input_path, input_pathp); 1713 if (nfiles == 0) 1714 printf(" not found\n"); 1715 else 1716 printf(" ambiguous\n"); 1717 error++; 1718 return; 1719 } 1720 } 1721 restore_inode(filenames->ino); 1722 freemem(filenames, nfiles); 1723 nfiles = 0; 1724 top = filenames - 1; 1725 if ((mode = icheck(addr)) == 0) 1726 return; 1727 if ((mode & IFMT) != IFDIR) { 1728 print_path(input_path, input_pathp); 1729 printf(" not a directory\n"); 1730 error++; 1731 return; 1732 } 1733 eat_spaces(); 1734 if ((c = getachar()) != '-') { 1735 printf("missing '-'\n"); 1736 error++; 1737 return; 1738 } 1739 find_by_name = find_by_inode = 0; 1740 c = getachar(); 1741 if (match("name", 4)) { 1742 eat_spaces(); 1743 find_by_name = 1; 1744 } else if (match("inum", 4)) { 1745 eat_spaces(); 1746 find_ino = expr(); 1747 if (error) 1748 return; 1749 while ((c = getachar()) != '\n') 1750 ; 1751 ungetachar(c); 1752 find_by_inode = 1; 1753 } else { 1754 printf("use -name or -inum with find\n"); 1755 error++; 1756 return; 1757 } 1758 doing_find = 1; 1759 parse(); 1760 doing_find = 0; 1761 if (error) { 1762 restore_inode(temp); 1763 return; 1764 } 1765 for (fn = filenames; fn <= top; fn++) { 1766 if (fn->find == 0) 1767 continue; 1768 printf("i#: "); 1769 print(fn->ino, 12, -8, 0); 1770 print_path(fn->fname, fn->len); 1771 printf("\n"); 1772 } 1773 restore_inode(temp); 1774 } 1775 1776 /* 1777 * ls - do an ls. Should behave exactly as ls(1). 1778 * Only -R and -l is supported and -l gives different results. 1779 */ 1780 ls(fn0, fnlast, level) 1781 struct filenames *fn0, *fnlast; 1782 short level; 1783 { 1784 register struct filenames *fn, *fnn; 1785 register int i; 1786 int fcmp(); 1787 1788 fn = fn0; 1789 for (;;) { 1790 fn0 = fn; 1791 if (fn0->len) { 1792 cmp_level = level; 1793 qsort((char *)fn0, fnlast - fn0 + 1, 1794 sizeof (struct filenames), fcmp); 1795 } 1796 for (fnn = fn, fn++; fn <= fnlast; fnn = fn, fn++) { 1797 if (fnn->len != fn->len && level == fnn->len - 1) 1798 break; 1799 if (fnn->len == 0) 1800 continue; 1801 if (strcmp(fn->fname[level], fnn->fname[level])) 1802 break; 1803 } 1804 if (fn0->len && level != fn0->len - 1) 1805 ls(fn0, fnn, level + 1); 1806 else { 1807 if (fn0 != filenames) 1808 printf("\n"); 1809 print_path(fn0->fname, fn0->len - 1); 1810 printf(":\n"); 1811 if (fn0->len == 0) 1812 cmp_level = level; 1813 else 1814 cmp_level = level + 1; 1815 qsort((char *)fn0, fnn - fn0 + 1, 1816 sizeof (struct filenames), fcmp); 1817 formatf(fn0, fnn); 1818 nfiles -= fnn - fn0 + 1; 1819 } 1820 if (fn > fnlast) 1821 return; 1822 } 1823 } 1824 1825 /* 1826 * formatf - code lifted from ls. 1827 */ 1828 formatf(fn0, fnlast) 1829 register struct filenames *fn0, *fnlast; 1830 { 1831 register struct filenames *fn; 1832 int width = 0, w, nentry = fnlast - fn0 + 1; 1833 int i, j, columns, lines; 1834 char *cp; 1835 1836 if (long_list) { 1837 columns = 1; 1838 } else { 1839 for (fn = fn0; fn <= fnlast; fn++) { 1840 int len = strlen(fn->fname[cmp_level]) + 2; 1841 1842 if (len > width) 1843 width = len; 1844 } 1845 width = (width + 8) &~ 7; 1846 columns = 80 / width; 1847 if (columns == 0) 1848 columns = 1; 1849 } 1850 lines = (nentry + columns - 1) / columns; 1851 for (i = 0; i < lines; i++) { 1852 for (j = 0; j < columns; j++) { 1853 fn = fn0 + j * lines + i; 1854 if (long_list) { 1855 printf("i#: "); 1856 print(fn->ino, 12, -8, 0); 1857 } 1858 cp = fmtentry(fn); 1859 printf("%s", cp); 1860 if (fn + lines > fnlast) { 1861 printf("\n"); 1862 break; 1863 } 1864 w = strlen(cp); 1865 while (w < width) { 1866 w = (w + 8) &~ 7; 1867 putchar('\t'); 1868 } 1869 } 1870 } 1871 } 1872 1873 /* 1874 * fmtentry - code lifted from ls. 1875 */ 1876 char * 1877 fmtentry(fn) 1878 register struct filenames *fn; 1879 { 1880 static char fmtres[BUFSIZ]; 1881 register struct dinode *ip; 1882 register char *cptr, *cp, *dp; 1883 1884 dp = &fmtres[0]; 1885 for (cp = fn->fname[cmp_level]; *cp; cp++) { 1886 if (*cp < ' ' || *cp >= 0177) 1887 *dp++ = '?'; 1888 else 1889 *dp++ = *cp; 1890 } 1891 addr = itob(fn->ino); 1892 if ((cptr = getblk(addr)) == 0) 1893 return(NULL); 1894 cptr += blkoff(fs, addr); 1895 ip = (struct dinode *)cptr; 1896 switch (ip->di_mode & IFMT) { 1897 case IFDIR: 1898 *dp++ = '/'; 1899 break; 1900 case IFLNK: 1901 *dp++ = '@'; 1902 break; 1903 case IFSOCK: 1904 *dp++ = '='; 1905 break; 1906 #ifdef IFIFO 1907 case IFIFO: 1908 *dp++ = 'p'; 1909 break; 1910 #endif 1911 case IFCHR: 1912 case IFBLK: 1913 case IFREG: 1914 if (ip->di_mode & 0111) 1915 *dp++ = '*'; 1916 else 1917 *dp++ = ' '; 1918 break; 1919 default: 1920 *dp++ = '?'; 1921 1922 } 1923 *dp++ = 0; 1924 return (fmtres); 1925 } 1926 1927 /* 1928 * fcmp - routine used by qsort. Will sort first by name, then 1929 * then by pathname length if names are equal. Uses global 1930 * cmp_level to tell what component of the path name we are comparing. 1931 */ 1932 fcmp(f1, f2) 1933 register struct filenames *f1, *f2; 1934 { 1935 int value; 1936 1937 if ((value = strcmp(f1->fname[cmp_level], f2->fname[cmp_level]))) 1938 return(value); 1939 return (f1->len - f2->len); 1940 } 1941 1942 /* 1943 * ffcmp - routine used by qsort. Sort only by pathname length. 1944 */ 1945 ffcmp(f1, f2) 1946 register struct filenames *f1, *f2; 1947 { 1948 return (f1->len - f2->len); 1949 } 1950 1951 /* 1952 * parse - set up the call to follow_path. 1953 */ 1954 parse() 1955 { 1956 register int i, j; 1957 char c; 1958 1959 stack_pathp = input_pathp = -1; 1960 if ((c = getachar()) == '/') { 1961 while ((c = getachar()) == '/') 1962 ; 1963 ungetachar(c); 1964 cur_inum = 2; 1965 if ((c = getachar()) == '\n') { 1966 ungetachar('\n'); 1967 if (doing_cd) { 1968 top++; 1969 top->ino = 2; 1970 top->len = -1; 1971 nfiles = 1; 1972 return; 1973 } 1974 } else 1975 ungetachar(c); 1976 } else { 1977 ungetachar(c); 1978 stack_pathp = current_pathp; 1979 if (!doing_find) 1980 input_pathp = current_pathp; 1981 for (i = 0; i <= current_pathp; i++) { 1982 if (!doing_find) 1983 strcpy(input_path[i], current_path[i]); 1984 strcpy(stack_path[i], current_path[i]); 1985 } 1986 } 1987 getname(); 1988 follow_path(stack_pathp + 1, cur_inum); 1989 } 1990 1991 /* 1992 * follow_path - called by cd, find, and ls. 1993 * input_path holds the name typed by the user. 1994 * stack_path holds the name at the current depth. 1995 */ 1996 follow_path(level, inum) 1997 long level, inum; 1998 { 1999 register struct direct *dirp; 2000 register char **ccptr, *cptr, c; 2001 register int i; 2002 struct filenames *tos, *bos, *fn, *fnn, *fnnn; 2003 long block; 2004 short mode; 2005 2006 tos = top + 1; 2007 restore_inode(inum); 2008 if ((mode = icheck(addr)) == 0) 2009 return; 2010 if ((mode & IFMT) != IFDIR) 2011 return; 2012 block = cur_bytes = 0; 2013 while (cur_bytes < filesize) { 2014 if (block == 0 || bcomp(addr)) { 2015 error = 0; 2016 if ((addr = (bmap(block++) << FRGSHIFT)) == 0) 2017 break; 2018 if ((cptr = getblk(addr)) == 0) 2019 break; 2020 cptr += blkoff(fs, addr); 2021 } 2022 dirp = (struct direct *)cptr; 2023 if (dirp->d_ino) { 2024 if (level > input_pathp || doing_find || 2025 compare(input_path[level], &dirp->d_name[0], 1)) { 2026 if (++top - filenames >= MAXFILES) { 2027 printf("too many files\n"); 2028 error++; 2029 return; 2030 } 2031 top->fname = (char **)calloc(FIRST_DEPTH, sizeof (char **)); 2032 top->flag = 0; 2033 if (top->fname == 0) { 2034 printf("out of memory\n"); 2035 error++; 2036 return; 2037 } 2038 nfiles++; 2039 top->ino = dirp->d_ino; 2040 top->len = stack_pathp; 2041 top->find = 0; 2042 if (doing_find) { 2043 if (find_by_name) { 2044 if (compare(input_path[0], &dirp->d_name[0], 1)) 2045 top->find = 1; 2046 } else if (find_by_inode) 2047 if (find_ino == dirp->d_ino) 2048 top->find = 1; 2049 } 2050 if (top->len + 1 >= FIRST_DEPTH && top->flag == 0) { 2051 ccptr = (char **)calloc(SECOND_DEPTH, sizeof (char **)); 2052 if (ccptr == 0) { 2053 printf("out of memory\n"); 2054 error++; 2055 return; 2056 } 2057 for (i = 0; i < FIRST_DEPTH; i++) 2058 ccptr[i] = top->fname[i]; 2059 free((char *)top->fname); 2060 top->fname = ccptr; 2061 top->flag = 1; 2062 } 2063 if (top->len >= SECOND_DEPTH) { 2064 printf("maximum depth exceeded, try to cd lower\n"); 2065 error++; 2066 return; 2067 } 2068 /* 2069 * Copy current depth. 2070 */ 2071 for (i = 0; i <= stack_pathp; i++) { 2072 top->fname[i]=calloc(1, strlen(stack_path[i])+1); 2073 if (top->fname[i] == 0) { 2074 printf("out of memory\n"); 2075 error++; 2076 return; 2077 } 2078 strcpy(top->fname[i], stack_path[i]); 2079 } 2080 /* 2081 * Check for '.' or '..' typed. 2082 */ 2083 if ((level <= input_pathp) && 2084 (strcmp(input_path[level], ".") == 0 || 2085 strcmp(input_path[level], "..") == 0)) { 2086 if (strcmp(input_path[level],"..") == 0 && 2087 top->len >= 0) { 2088 free(top->fname[top->len]); 2089 top->len -= 1; 2090 } 2091 } else { 2092 /* 2093 * Check for duplicates. 2094 */ 2095 if (!doing_cd && !doing_find) { 2096 for (fn = filenames; fn < top; fn++) { 2097 if (fn->ino == dirp->d_ino && 2098 fn->len == stack_pathp + 1) { 2099 for (i = 0; i < fn->len; i++) 2100 if (strcmp(fn->fname[i], stack_path[i])) 2101 break; 2102 if (i != fn->len || 2103 strcmp(fn->fname[i], dirp->d_name)) 2104 continue; 2105 freemem(top, 1); 2106 if (top == filenames) 2107 top = NULL; 2108 else 2109 top--; 2110 nfiles--; 2111 goto duplicate; 2112 } 2113 } 2114 } 2115 top->len += 1; 2116 top->fname[top->len] = calloc(1, 2117 strlen(&dirp->d_name[0])+1); 2118 if (top->fname[top->len] == 0) { 2119 printf("out of memory\n"); 2120 error++; 2121 return; 2122 } 2123 strcpy(top->fname[top->len], &dirp->d_name[0]); 2124 } 2125 } 2126 } 2127 duplicate: 2128 addr += dirp->d_reclen; 2129 cptr += dirp->d_reclen; 2130 cur_bytes += dirp->d_reclen; 2131 } 2132 if (top < filenames) 2133 return; 2134 if ((doing_cd && level == input_pathp) || 2135 (!recursive && !doing_find && level > input_pathp)) 2136 return; 2137 bos = top; 2138 /* 2139 * Check newly added entries to determine if further expansion 2140 * is required. 2141 */ 2142 for (fn = tos; fn <= bos; fn++) { 2143 /* 2144 * Avoid '.' and '..' if beyond input. 2145 */ 2146 if ((recursive || doing_find) && (level > input_pathp) && 2147 (strcmp(fn->fname[fn->len], ".") == 0 || 2148 strcmp(fn->fname[fn->len], "..") == 0)) 2149 continue; 2150 restore_inode(fn->ino); 2151 if ((mode = icheck(cur_ino)) == 0) 2152 return; 2153 if ((mode & IFMT) == IFDIR || level < input_pathp) { 2154 /* 2155 * Set up current depth, remove current entry and 2156 * continue recursion. 2157 */ 2158 for (i = 0; i <= fn->len; i++) 2159 strcpy(stack_path[i], fn->fname[i]); 2160 stack_pathp = fn->len; 2161 if (!doing_find && 2162 (!recursive || (recursive && level <= input_pathp))) { 2163 /* 2164 * Remove current entry by moving others up. 2165 */ 2166 freemem(fn, 1); 2167 fnn = fn; 2168 for (fnnn = fnn, fnn++; fnn <= top; fnnn = fnn, fnn++) { 2169 fnnn->ino = fnn->ino; 2170 fnnn->len = fnn->len; 2171 if (fnnn->len + 1 < FIRST_DEPTH) { 2172 fnnn->fname = (char **)calloc(FIRST_DEPTH, 2173 sizeof (char **)); 2174 fnnn->flag = 0; 2175 } else if (fnnn->len < SECOND_DEPTH) { 2176 fnnn->fname = (char **)calloc(SECOND_DEPTH, 2177 sizeof (char **)); 2178 fnnn->flag = 1; 2179 } else { 2180 printf("maximum depth exceeded, "); 2181 printf("try to cd lower\n"); 2182 error++; 2183 return; 2184 } 2185 for (i = 0; i <= fnn->len; i++) 2186 fnnn->fname[i] = fnn->fname[i]; 2187 } 2188 if (fn == tos) 2189 fn--; 2190 top--; 2191 bos--; 2192 nfiles--; 2193 } 2194 follow_path(level + 1, cur_inum); 2195 if (error) 2196 return; 2197 } 2198 } 2199 } 2200 2201 /* 2202 * getname - break up the pathname entered by the user into components. 2203 */ 2204 getname() 2205 { 2206 register int i; 2207 char c; 2208 2209 if ((c = getachar()) == '\n') { 2210 ungetachar(c); 2211 return; 2212 } 2213 ungetachar(c); 2214 input_pathp++; 2215 clear: 2216 for (i = 0; i < MAXNAMLEN; i++) 2217 input_path[input_pathp][i] = '\0'; 2218 for (;;) { 2219 c = getachar(); 2220 if (c == '\\') { 2221 if (strlen(input_path[input_pathp]) + 1 >= MAXNAMLEN) { 2222 printf("maximum name length exceeded, "); 2223 printf("truncating\n"); 2224 return; 2225 } 2226 input_path[input_pathp][strlen(input_path[input_pathp])] = c; 2227 input_path[input_pathp][strlen(input_path[input_pathp])] = 2228 getachar(); 2229 continue; 2230 } 2231 if (c == ' ' || c == '\n') { 2232 ungetachar(c); 2233 return; 2234 } 2235 if (!doing_find && c == '/') { 2236 if (++input_pathp >= MAXPATHLEN) { 2237 printf("maximum path length exceeded, "); 2238 printf("truncating\n"); 2239 input_pathp--; 2240 return; 2241 } 2242 goto clear; 2243 } 2244 if (strlen(input_path[input_pathp]) >= MAXNAMLEN) { 2245 printf("maximum name length exceeded, truncating\n"); 2246 return; 2247 } 2248 input_path[input_pathp][strlen(input_path[input_pathp])] = c; 2249 } 2250 } 2251 2252 /* 2253 * compare - check if a filename matches the pattern entered by the user. 2254 * Handles '*', '?', and '[]'. 2255 */ 2256 compare(s1, s2, at_start) 2257 char *s1, *s2; 2258 short at_start; 2259 { 2260 register char c, *s; 2261 2262 s = s2; 2263 while (c = *s1) { 2264 if (c == '*') { 2265 if (at_start && s == s2 && !letter(*s2) && !digit(*s2)) 2266 return(0); 2267 if (*++s1 == 0) 2268 return(1); 2269 while (*s2) { 2270 if (compare(s1, s2, 0)) 2271 return(1); 2272 if (error) 2273 return(0); 2274 s2++; 2275 } 2276 } 2277 if (*s2 == 0) 2278 return(0); 2279 if (c == '\\') { 2280 s1++; 2281 goto compare_chars; 2282 } 2283 if (c == '?') { 2284 if (at_start && s == s2 && !letter(*s2) && !digit(*s2)) 2285 return(0); 2286 s1++; 2287 s2++; 2288 continue; 2289 } 2290 if (c == '[') { 2291 s1++; 2292 if (*s2 >= *s1++) { 2293 if (*s1++ != '-') { 2294 printf("missing '-'\n"); 2295 error++; 2296 return(0); 2297 } 2298 if (*s2 <= *s1++) { 2299 if (*s1++ != ']') { 2300 printf("missing ']'"); 2301 error++; 2302 return(0); 2303 } 2304 s2++; 2305 continue; 2306 } 2307 } 2308 } 2309 compare_chars: 2310 if (*s1++ == *s2++) 2311 continue; 2312 else 2313 return(0); 2314 } 2315 if (*s1 == *s2) 2316 return(1); 2317 return(0); 2318 } 2319 2320 /* 2321 * freemem - free the memory allocated to the filenames structure. 2322 */ 2323 freemem(p, numb) 2324 struct filenames *p; 2325 int numb; 2326 { 2327 register int i, j; 2328 2329 if (numb == 0) 2330 return; 2331 for (i = 0; i < numb; i++, p++) { 2332 for (j = 0; j <= p->len; j++) 2333 free(p->fname[j]); 2334 free((char *)p->fname); 2335 } 2336 } 2337 2338 /* 2339 * print_path - print the pathname held in p. 2340 */ 2341 print_path(p, pntr) 2342 char *p[]; 2343 short pntr; 2344 { 2345 register int i; 2346 2347 printf("/"); 2348 if (pntr >= 0) { 2349 for (i = 0; i < pntr; i++) 2350 printf("%s/", p[i]); 2351 printf("%s", p[pntr]); 2352 } 2353 } 2354 2355 /* 2356 * fill - fill a section with a value or string. 2357 * addr,count:fill=[value, "string"]. 2358 */ 2359 fill() 2360 { 2361 register char *cptr; 2362 register int i; 2363 short eof_flag, end = 0, eof = 0; 2364 long temp, tcount, taddr; 2365 2366 if (!wrtflag) { 2367 printf("not opened for write '-w'\n"); 2368 error++; 2369 return; 2370 } 2371 temp = expr(); 2372 if (error) 2373 return; 2374 if ((cptr = getblk(addr)) == 0) 2375 return; 2376 if (type == NUMB) 2377 eof_flag = 0; 2378 else 2379 eof_flag = 1; 2380 taddr = addr; 2381 switch (objsz) { 2382 case LONG: 2383 addr &= ~(LONG - 1); 2384 break; 2385 case SHORT: 2386 addr &= ~(SHORT - 1); 2387 temp &= 0177777L; 2388 break; 2389 case CHAR: 2390 temp &= 0377; 2391 } 2392 cur_bytes -= taddr - addr; 2393 cptr += blkoff(fs, addr); 2394 tcount = check_addr(eof_flag, &end, &eof, 0); 2395 for (i = 0; i < tcount; i++) { 2396 switch (objsz) { 2397 case LONG: 2398 *(long *)cptr = temp; 2399 break; 2400 case SHORT: 2401 *(short *)cptr = temp; 2402 break; 2403 case CHAR: 2404 *cptr = temp; 2405 } 2406 cptr += objsz; 2407 } 2408 addr += (tcount - 1) * objsz; 2409 cur_bytes += (tcount - 1) * objsz; 2410 put(temp, objsz); 2411 if (eof) { 2412 printf("end of file\n"); 2413 error++; 2414 } else if (end) { 2415 printf("end of block\n"); 2416 error++; 2417 } 2418 } 2419 2420 /* 2421 * get - read a byte, short or long from the file system. 2422 * The entire block containing the desired item is read 2423 * and the appropriate data is extracted and returned. 2424 */ 2425 long 2426 get(lngth) 2427 short lngth; 2428 { 2429 2430 register char *bptr; 2431 long temp = addr; 2432 2433 objsz = lngth; 2434 if (objsz == INODE || objsz == SHORT) 2435 temp &= ~(SHORT - 1); 2436 else if (objsz == DIRECTORY || objsz == LONG) 2437 temp &= ~(LONG - 1); 2438 if ((bptr = getblk(temp)) == 0) 2439 return(-1); 2440 bptr += blkoff(fs, temp); 2441 switch (objsz) { 2442 case CHAR: 2443 return((long)*bptr); 2444 case SHORT: 2445 case INODE: 2446 return((long)(*(short *)bptr)); 2447 case LONG: 2448 case DIRECTORY: 2449 return(*(long *)bptr); 2450 } 2451 return(0); 2452 } 2453 2454 /* 2455 * cgrp_check - make sure that we don't bump the cylinder group 2456 * beyond the total number of cylinder groups or before the start. 2457 */ 2458 cgrp_check(cgrp) 2459 long cgrp; 2460 { 2461 if (cgrp < 0) { 2462 if (objsz == CGRP) 2463 printf("beginning of cylinder groups\n"); 2464 else 2465 printf("beginning of super blocks\n"); 2466 error++; 2467 return(0); 2468 } 2469 if (cgrp >= fs->fs_ncg) { 2470 if (objsz == CGRP) 2471 printf("end of cylinder groups\n"); 2472 else 2473 printf("end of super blocks\n"); 2474 error++; 2475 return(0); 2476 } 2477 if (objsz == CGRP) 2478 return(cgtod(fs, cgrp) << FRGSHIFT); 2479 else 2480 return(cgsblock(fs, cgrp) << FRGSHIFT); 2481 } 2482 2483 /* 2484 * icheck - make sure we can read the block containing the inode 2485 * and determine the filesize (0 if inode not allocated). Return 2486 * 0 if error otherwise return the mode. 2487 */ 2488 icheck(address) 2489 long address; 2490 { 2491 register char *cptr; 2492 register struct dinode *ip; 2493 2494 if ((cptr = getblk(address)) == 0) 2495 return(0); 2496 cptr += blkoff(fs, address); 2497 ip = (struct dinode *)cptr; 2498 if ((ip->di_mode & IFMT) == 0) { 2499 if (!override) { 2500 printf("inode not allocated\n"); 2501 error++; 2502 return(0); 2503 } 2504 blocksize = filesize = 0; 2505 } else { 2506 trapped++; 2507 filesize = ip->di_size; 2508 blocksize = filesize * 2; 2509 } 2510 return(ip->di_mode); 2511 } 2512 2513 /* 2514 * getdirslot - get the address of the directory slot desired. 2515 */ 2516 getdirslot(slot) 2517 short slot; 2518 { 2519 register char *cptr; 2520 register struct direct *dirp; 2521 register short i; 2522 char *string = &scratch[0]; 2523 short bod = 0, mode, temp; 2524 2525 if (slot < 0) { 2526 slot = 0; 2527 bod++; 2528 } 2529 if (type != DIRECTORY) { 2530 if (type == BLOCK) 2531 string = "block"; 2532 else 2533 string = "fragment"; 2534 addr = bod_addr; 2535 if ((cptr = getblk(addr)) == 0) 2536 return(0); 2537 cptr += blkoff(fs, addr); 2538 cur_bytes = 0; 2539 dirp = (struct direct *)cptr; 2540 for (dirslot = 0; dirslot < slot; dirslot++) { 2541 dirp = (struct direct *)cptr; 2542 if (blocksize > filesize) { 2543 if (cur_bytes + dirp->d_reclen >= filesize) { 2544 printf("end of file\n"); 2545 erraddr = addr; 2546 errcur_bytes = cur_bytes; 2547 stringsize = STRINGSIZE(dirp); 2548 error++; 2549 return(addr); 2550 } 2551 } else { 2552 if (cur_bytes + dirp->d_reclen >= blocksize) { 2553 printf("end of %s\n", string); 2554 erraddr = addr; 2555 errcur_bytes = cur_bytes; 2556 stringsize = STRINGSIZE(dirp); 2557 error++; 2558 return(addr); 2559 } 2560 } 2561 cptr += dirp->d_reclen; 2562 addr += dirp->d_reclen; 2563 cur_bytes += dirp->d_reclen; 2564 } 2565 if (bod) { 2566 if (blocksize > filesize) 2567 printf("beginning of file\n"); 2568 else 2569 printf("beginning of %s\n", string); 2570 erraddr = addr; 2571 errcur_bytes = cur_bytes; 2572 error++; 2573 } 2574 stringsize = STRINGSIZE(dirp); 2575 return(addr); 2576 } else { 2577 addr = cur_ino; 2578 if ((mode = icheck(addr)) == 0) 2579 return(0); 2580 if (!override && (mode & IFDIR) == 0) { 2581 printf("inode is not a directory\n"); 2582 error++; 2583 return(0); 2584 } 2585 temp = slot; 2586 i = cur_bytes = 0; 2587 for (;;) { 2588 if (i == 0 || bcomp(addr)) { 2589 error = 0; 2590 if ((addr=(bmap(i++) << FRGSHIFT)) == 0) 2591 break; 2592 if ((cptr = getblk(addr)) == 0) 2593 break; 2594 cptr += blkoff(fs, addr); 2595 } 2596 dirp = (struct direct *)cptr; 2597 value = dirp->d_ino; 2598 if (!temp--) 2599 break; 2600 if (cur_bytes + dirp->d_reclen >= filesize) { 2601 printf("end of file\n"); 2602 dirslot = slot - temp - 1; 2603 objsz = DIRECTORY; 2604 erraddr = addr; 2605 errcur_bytes = cur_bytes; 2606 stringsize = STRINGSIZE(dirp); 2607 error++; 2608 return(addr); 2609 } 2610 addr += dirp->d_reclen; 2611 cptr += dirp->d_reclen; 2612 cur_bytes += dirp->d_reclen; 2613 } 2614 dirslot = slot; 2615 objsz = DIRECTORY; 2616 if (bod) { 2617 printf("beginning of file\n"); 2618 erraddr = addr; 2619 errcur_bytes = cur_bytes; 2620 error++; 2621 } 2622 stringsize = STRINGSIZE(dirp); 2623 return(addr); 2624 } 2625 } 2626 2627 /* 2628 * putf - print a byte as an ascii character if possible. 2629 * The exceptions are tabs, newlines, backslashes 2630 * and nulls which are printed as the standard C 2631 * language escapes. Characters which are not 2632 * recognized are printed as \?. 2633 */ 2634 putf(c) 2635 register char c; 2636 { 2637 2638 if (c<=037 || c>=0177 || c=='\\') { 2639 printf("\\"); 2640 switch (c) { 2641 case '\\': 2642 printf("\\"); 2643 break; 2644 case '\t': 2645 printf("t"); 2646 break; 2647 case '\n': 2648 printf("n"); 2649 break; 2650 case '\0': 2651 printf("0"); 2652 break; 2653 default: 2654 printf("?"); 2655 } 2656 } 2657 else { 2658 printf("%c", c); 2659 printf(" "); 2660 } 2661 } 2662 2663 /* 2664 * put - write an item into the buffer for the current address 2665 * block. The value is checked to make sure that it will 2666 * fit in the size given without truncation. If successful, 2667 * the entire block is written back to the file system. 2668 */ 2669 put(item,lngth) 2670 long item; 2671 short lngth; 2672 { 2673 2674 register char *bptr, *sbptr; 2675 register long *vptr; 2676 long s_err,nbytes; 2677 long olditem; 2678 2679 if (!wrtflag) { 2680 printf("not opened for write '-w'\n"); 2681 error++; 2682 return; 2683 } 2684 objsz = lngth; 2685 if ((sbptr = getblk(addr)) == 0) 2686 return; 2687 bptr = sbptr + blkoff(fs, addr); 2688 switch (objsz) { 2689 case LONG: 2690 case DIRECTORY: 2691 olditem = *(long *)bptr; 2692 *(long *)bptr = item; 2693 break; 2694 case SHORT: 2695 case INODE: 2696 olditem = (long)*(short *)bptr; 2697 item &= 0177777L; 2698 *(short *)bptr = item; 2699 break; 2700 case CHAR: 2701 olditem = (long)*bptr; 2702 item &= 0377; 2703 *bptr = lobyte(loword(item)); 2704 break; 2705 default: 2706 error++; 2707 return; 2708 } 2709 if ((s_err = lseek(fd, addr & fs->fs_bmask, 0)) == -1) { 2710 error++; 2711 printf("seek error : %x\n",addr); 2712 return(0); 2713 } 2714 if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) { 2715 error++; 2716 printf("write error : addr = %x\n",addr); 2717 printf(" : s_err = %x\n",s_err); 2718 printf(" : nbytes = %x\n",nbytes); 2719 return(0); 2720 } 2721 if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) { 2722 index(base); 2723 print(olditem, 8, -8, 0); 2724 printf("\t=\t"); 2725 print(item, 8, -8, 0); 2726 printf("\n"); 2727 } else { 2728 if (objsz == DIRECTORY) { 2729 addr = cur_dir; 2730 fprnt('?', 'd'); 2731 } else { 2732 addr = cur_ino; 2733 objsz = INODE; 2734 fprnt('?', 'i'); 2735 } 2736 } 2737 return; 2738 } 2739 2740 /* 2741 * getblk - check if the desired block is in the file system. 2742 * Search the incore buffers to see if the block is already 2743 * available. If successful, unlink the buffer control block 2744 * from its position in the buffer list and re-insert it at 2745 * the head of the list. If failure, use the last buffer 2746 * in the list for the desired block. Again, this control 2747 * block is placed at the head of the list. This process 2748 * will leave commonly requested blocks in the in-core buffers. 2749 * Finally, a pointer to the buffer is returned. 2750 */ 2751 char * 2752 getblk(address) 2753 long address; 2754 { 2755 2756 register struct buf *bp; 2757 long s_err, nbytes; 2758 unsigned long block; 2759 2760 read_requests++; 2761 block = lblkno(fs, address); 2762 if (block >= fragstoblks(fs, fs->fs_size)) { 2763 printf("block exceeds maximum block in file system\n"); 2764 error++; 2765 return(0); 2766 } 2767 for (bp=bhdr.fwd; bp!= &bhdr; bp=bp->fwd) 2768 if (bp->valid && bp->blkno==block) 2769 goto xit; 2770 actual_disk_reads++; 2771 bp = bhdr.back; 2772 bp->blkno = block; 2773 bp->valid = 0; 2774 if ((s_err = lseek(fd, address & fs->fs_bmask, 0)) == -1) { 2775 error++; 2776 printf("seek error : %x\n",address); 2777 return(0); 2778 } 2779 if ((nbytes = read(fd, bp->blkaddr, BLKSIZE)) != BLKSIZE) { 2780 error++; 2781 printf("read error : addr = %x\n",address); 2782 printf(" : s_err = %x\n",s_err); 2783 printf(" : nbytes = %x\n",nbytes); 2784 return(0); 2785 } 2786 bp->valid++; 2787 xit: bp->back->fwd = bp->fwd; 2788 bp->fwd->back = bp->back; 2789 insert(bp); 2790 return(bp->blkaddr); 2791 } 2792 2793 /* 2794 * insert - place the designated buffer control block 2795 * at the head of the linked list of buffers. 2796 */ 2797 insert(bp) 2798 register struct buf *bp; 2799 { 2800 2801 bp->back = &bhdr; 2802 bp->fwd = bhdr.fwd; 2803 bhdr.fwd->back = bp; 2804 bhdr.fwd = bp; 2805 } 2806 2807 /* 2808 * err - called on interrupts. Set the current address 2809 * back to the last address stored in erraddr. Reset all 2810 * appropriate flags. A reset call is made to return 2811 * to the main loop; 2812 */ 2813 void 2814 err() 2815 { 2816 freemem(filenames, nfiles); 2817 nfiles = 0; 2818 signal(2,err); 2819 addr = erraddr; 2820 cur_ino = errino; 2821 cur_inum = errinum; 2822 cur_bytes = errcur_bytes; 2823 error = 0; 2824 c_count = 0; 2825 printf("\n?\n"); 2826 fseek(stdin, 0L, 2); 2827 longjmp(env,0); 2828 } 2829 2830 /* 2831 * devcheck - check that the given mode represents a 2832 * special device. The IFCHR bit is on for both 2833 * character and block devices. 2834 */ 2835 devcheck(md) 2836 register short md; 2837 { 2838 if (override) 2839 return(0); 2840 if (md & IFCHR) 2841 return(0); 2842 printf("not character or block device\n"); 2843 error++; 2844 return(1); 2845 } 2846 2847 /* 2848 * nullblk - return error if address is zero. This is done 2849 * to prevent block 0 from being used as an indirect block 2850 * for a large file or as a data block for a small file. 2851 */ 2852 nullblk(bn) 2853 long bn; 2854 { 2855 if (bn != 0) 2856 return(0); 2857 printf("non existent block\n"); 2858 error++; 2859 return(1); 2860 } 2861 2862 /* 2863 * puta - put ascii characters into a buffer. The string 2864 * terminates with a quote or newline. The leading quote, 2865 * which is optional for directory names, was stripped off 2866 * by the assignment case in the main loop. 2867 */ 2868 puta() 2869 { 2870 register char *cptr, c; 2871 register int i; 2872 char *sbptr; 2873 short terror = 0; 2874 long maxchars, s_err, nbytes, temp; 2875 long taddr = addr, tcount = 0, item, olditem = 0; 2876 2877 if (!wrtflag) { 2878 printf("not opened for write '-w'\n"); 2879 error++; 2880 return; 2881 } 2882 if ((sbptr = getblk(addr)) == 0) 2883 return; 2884 cptr = sbptr + blkoff(fs, addr); 2885 if (objsz == DIRECTORY) { 2886 if (acting_on_directory) 2887 maxchars = stringsize - 1; 2888 else 2889 maxchars = LONG; 2890 } else if (objsz == INODE) 2891 maxchars = objsz - (addr - cur_ino); 2892 else 2893 maxchars = min(blocksize - cur_bytes, filesize - cur_bytes); 2894 while ((c = getachar()) != '"') { 2895 if (tcount >= maxchars) { 2896 printf("string too long\n"); 2897 if (objsz == DIRECTORY) 2898 addr = cur_dir; 2899 else if (acting_on_inode || objsz == INODE) 2900 addr = cur_ino; 2901 else 2902 addr = taddr; 2903 erraddr = addr; 2904 errcur_bytes = cur_bytes; 2905 terror++; 2906 break; 2907 } 2908 tcount++; 2909 if (c == '\n') { 2910 ungetachar(c); 2911 break; 2912 } 2913 temp = (long)*cptr; 2914 olditem <<= BITSPERCHAR; 2915 olditem += temp & 0xff; 2916 if (c == '\\') { 2917 switch (c = getachar()) { 2918 case 't': 2919 *cptr++ = '\t'; 2920 break; 2921 case 'n': 2922 *cptr++ = '\n'; 2923 break; 2924 case '0': 2925 *cptr++ = '\0'; 2926 break; 2927 default: 2928 *cptr++ = c; 2929 break; 2930 } 2931 } 2932 else 2933 *cptr++ = c; 2934 } 2935 if (objsz == DIRECTORY && acting_on_directory) 2936 for (i = tcount; i <= maxchars; i++) 2937 *cptr++ = '\0'; 2938 if ((s_err = lseek(fd, addr & fs->fs_bmask, 0)) == -1) { 2939 error++; 2940 printf("seek error : %x\n",addr); 2941 return(0); 2942 } 2943 if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) { 2944 error++; 2945 printf("write error : addr = %x\n",addr); 2946 printf(" : s_err = %x\n",s_err); 2947 printf(" : nbytes = %x\n",nbytes); 2948 return(0); 2949 } 2950 if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) { 2951 addr += tcount; 2952 cur_bytes += tcount; 2953 taddr = addr; 2954 if (objsz != CHAR) { 2955 addr &= ~(objsz - 1); 2956 cur_bytes -= taddr - addr; 2957 } 2958 if (addr == taddr) { 2959 addr -= objsz; 2960 taddr = addr; 2961 } 2962 tcount = LONG - (taddr - addr); 2963 index(base); 2964 if ((cptr = getblk(addr)) == 0) 2965 return; 2966 cptr += blkoff(fs, addr); 2967 switch (objsz) { 2968 case LONG: 2969 item = *(long *)cptr; 2970 if (tcount < LONG) { 2971 olditem <<= tcount * BITSPERCHAR; 2972 temp = 1; 2973 for (i = 0; i < (tcount*BITSPERCHAR); i++) 2974 temp <<= 1; 2975 olditem += item & (temp - 1); 2976 } 2977 break; 2978 case SHORT: 2979 item = (long)*(short *)cptr; 2980 if (tcount < SHORT) { 2981 olditem <<= tcount * BITSPERCHAR; 2982 temp = 1; 2983 for (i = 0; i < (tcount * BITSPERCHAR); i++) 2984 temp <<= 1; 2985 olditem += item & (temp - 1); 2986 } 2987 olditem &= 0177777L; 2988 break; 2989 case CHAR: 2990 item = (long)*cptr; 2991 olditem &= 0377; 2992 } 2993 print(olditem, 8, -8, 0); 2994 printf("\t=\t"); 2995 print(item, 8, -8, 0); 2996 printf("\n"); 2997 } else { 2998 if (objsz == DIRECTORY) { 2999 addr = cur_dir; 3000 fprnt('?', 'd'); 3001 } else { 3002 addr = cur_ino; 3003 objsz = INODE; 3004 fprnt('?', 'i'); 3005 } 3006 } 3007 if (terror) 3008 error++; 3009 } 3010 3011 /* 3012 * fprnt - print data. 'count' elements are printed where '*' will 3013 * print an entire blocks worth or up to the eof, whichever 3014 * occurs first. An error will occur if crossing a block boundary 3015 * is attempted since consecutive blocks don't usually have 3016 * meaning. Current print types: 3017 * / b - print as bytes (base sensitive) 3018 * c - print as characters 3019 * o O - print as octal shorts (longs) 3020 * d D - print as decimal shorts (longs) 3021 * x X - print as hexadecimal shorts (longs) 3022 * ? c - print as cylinder groups 3023 * d - print as directories 3024 * i - print as inodes 3025 * s - print as super blocks 3026 */ 3027 fprnt(style, po) 3028 register char style, po; 3029 { 3030 register int i; 3031 register struct fs *sb; 3032 register struct cg *cg; 3033 register struct direct *dirp; 3034 register struct dinode *ip; 3035 int tbase; 3036 char c, *cptr, *p; 3037 long tinode, tcount, temp, taddr; 3038 short offset, mode, end = 0, eof = 0, eof_flag; 3039 unsigned short *sptr; 3040 unsigned long *lptr; 3041 3042 laststyle = style; 3043 lastpo = po; 3044 should_print = 0; 3045 if (count != 1) { 3046 if (clear) { 3047 count = 1; 3048 star = 0; 3049 clear = 0; 3050 } else 3051 clear = 1; 3052 } 3053 tcount = count; 3054 offset = blkoff(fs, addr); 3055 3056 if (style == '/') { 3057 if (type == NUMB) 3058 eof_flag = 0; 3059 else 3060 eof_flag = 1; 3061 switch (po) { 3062 3063 case 'c': /* print as characters */ 3064 case 'b': /* or bytes */ 3065 if ((cptr = getblk(addr)) == 0) 3066 return; 3067 cptr += offset; 3068 objsz = CHAR; 3069 tcount = check_addr(eof_flag, &end, &eof, 0); 3070 if (tcount) { 3071 for (i=0; tcount--; i++) { 3072 if (i % 16 == 0) { 3073 if (i) 3074 printf("\n"); 3075 index(base); 3076 } 3077 if (po == 'c') { 3078 putf(*cptr++); 3079 if ((i + 1) % 16) 3080 printf(" "); 3081 } else { 3082 if ((i + 1) % 16 == 0) 3083 print(*cptr++ & 0377, 3084 2,-2,0); 3085 else 3086 print(*cptr++ & 0377, 3087 4,-2,0); 3088 } 3089 addr += CHAR; 3090 cur_bytes += CHAR; 3091 } 3092 printf("\n"); 3093 } 3094 addr -= CHAR; 3095 erraddr = addr; 3096 cur_bytes -= CHAR; 3097 errcur_bytes = cur_bytes; 3098 if (eof) { 3099 printf("end of file\n"); 3100 error++; 3101 } else if (end) { 3102 if (type == BLOCK) 3103 printf("end of block\n"); 3104 else 3105 printf("end of fragment\n"); 3106 error++; 3107 } 3108 return; 3109 3110 case 'o': /* print as octal shorts */ 3111 tbase = OCTAL; 3112 goto otx; 3113 case 'd': /* print as decimal shorts */ 3114 tbase = DECIMAL; 3115 goto otx; 3116 case 'x': /* print as hex shorts */ 3117 tbase = HEX; 3118 otx: 3119 if ((cptr = getblk(addr)) == 0) 3120 return; 3121 taddr = addr; 3122 addr &= ~(SHORT - 1); 3123 cur_bytes -= taddr - addr; 3124 cptr += blkoff(fs, addr); 3125 sptr = (unsigned short *)cptr; 3126 objsz = SHORT; 3127 tcount = check_addr(eof_flag, &end, &eof, 0); 3128 if (tcount) { 3129 for (i=0; tcount--; i++) { 3130 sptr = (unsigned short *) 3131 print_check(sptr, &tcount, tbase, i); 3132 switch (po) { 3133 case 'o': 3134 printf("%06o ",*sptr++); 3135 break; 3136 case 'd': 3137 printf("%05d ",*sptr++); 3138 break; 3139 case 'x': 3140 printf("%04x ",*sptr++); 3141 } 3142 addr += SHORT; 3143 cur_bytes += SHORT; 3144 } 3145 printf("\n"); 3146 } 3147 addr -= SHORT; 3148 erraddr = addr; 3149 cur_bytes -= SHORT; 3150 errcur_bytes = cur_bytes; 3151 if (eof) { 3152 printf("end of file\n"); 3153 error++; 3154 } else if (end) { 3155 if (type == BLOCK) 3156 printf("end of block\n"); 3157 else 3158 printf("end of fragment\n"); 3159 error++; 3160 } 3161 return; 3162 3163 case 'O': /* print as octal longs */ 3164 tbase = OCTAL; 3165 goto OTX; 3166 case 'D': /* print as decimal longs */ 3167 tbase = DECIMAL; 3168 goto OTX; 3169 case 'X': /* print as hex longs */ 3170 tbase = HEX; 3171 OTX: 3172 if ((cptr = getblk(addr)) == 0) 3173 return; 3174 taddr = addr; 3175 addr &= ~(LONG - 1); 3176 cur_bytes -= taddr - addr; 3177 cptr += blkoff(fs, addr); 3178 lptr = (unsigned long *)cptr; 3179 objsz = LONG; 3180 tcount = check_addr(eof_flag, &end, &eof, 0); 3181 if (tcount) { 3182 for (i=0; tcount--; i++) { 3183 lptr = 3184 print_check(lptr, &tcount, tbase, i); 3185 switch (po) { 3186 case 'O': 3187 printf("%011o ",*lptr++); 3188 break; 3189 case 'D': 3190 printf("%010u ",*lptr++); 3191 break; 3192 case 'X': 3193 printf("%08x ",*lptr++); 3194 } 3195 addr += LONG; 3196 cur_bytes += LONG; 3197 } 3198 printf("\n"); 3199 } 3200 addr -= LONG; 3201 erraddr = addr; 3202 cur_bytes -= LONG; 3203 errcur_bytes = cur_bytes; 3204 if (eof) { 3205 printf("end of file\n"); 3206 error++; 3207 } else if (end) { 3208 if (type == BLOCK) 3209 printf("end of block\n"); 3210 else 3211 printf("end of fragment\n"); 3212 error++; 3213 } 3214 return; 3215 3216 default: 3217 error++; 3218 printf("no such print option\n"); 3219 return; 3220 } 3221 } else 3222 switch (po) { 3223 3224 case 'c': /* print as cylinder group */ 3225 if (type != NUMB) 3226 if (cur_cgrp + count > fs->fs_ncg) { 3227 tcount = fs->fs_ncg - cur_cgrp; 3228 if (!star) 3229 end++; 3230 } 3231 addr &= ~(LONG - 1); 3232 for (; tcount--;) { 3233 erraddr = addr; 3234 errcur_bytes = cur_bytes; 3235 if (type != NUMB) { 3236 addr = cgtod(fs, cur_cgrp) 3237 << FRGSHIFT; 3238 cur_cgrp++; 3239 } 3240 if ((cptr = getblk(addr)) == 0) { 3241 if (cur_cgrp) 3242 cur_cgrp--; 3243 return; 3244 } 3245 cptr += blkoff(fs, addr); 3246 cg = (struct cg *)cptr; 3247 if (type == NUMB) { 3248 cur_cgrp = cg->cg_cgx + 1; 3249 type = objsz = CGRP; 3250 if (cur_cgrp + count - 1 > fs->fs_ncg) { 3251 tcount = fs->fs_ncg - cur_cgrp; 3252 if (!star) 3253 end++; 3254 } 3255 } 3256 if (!override && !cg_chkmagic(cg)) { 3257 printf("invalid cylinder group "); 3258 printf("magic word\n"); 3259 if (cur_cgrp) 3260 cur_cgrp--; 3261 error++; 3262 return; 3263 } 3264 printcg(cg); 3265 if (tcount) 3266 printf("\n"); 3267 } 3268 cur_cgrp--; 3269 if (end) { 3270 printf("end of cylinder groups\n"); 3271 error++; 3272 } 3273 return; 3274 3275 case 'd': /* print as directories */ 3276 if ((cptr = getblk(addr)) == 0) 3277 return; 3278 if (type == NUMB) { 3279 if (fragoff(fs, addr)) { 3280 printf("address must be at the "); 3281 printf("beginning of a fragment\n"); 3282 error++; 3283 return; 3284 } 3285 bod_addr = addr; 3286 type = FRAGMENT; 3287 dirslot = 0; 3288 cur_bytes = 0; 3289 blocksize = FRGSIZE; 3290 filesize = FRGSIZE * 2; 3291 } 3292 cptr += offset; 3293 objsz = DIRECTORY; 3294 while (tcount-- && cur_bytes < filesize && 3295 cur_bytes < blocksize && !bcomp(addr)) { 3296 dirp = (struct direct *)cptr; 3297 tinode = dirp->d_ino; 3298 printf("i#: "); 3299 if (tinode == 0) 3300 printf("free\t"); 3301 else 3302 print(tinode, 12, -8, 0); 3303 printf("%s\n",&dirp->d_name[0]); 3304 erraddr = addr; 3305 errcur_bytes = cur_bytes; 3306 addr += dirp->d_reclen; 3307 cptr += dirp->d_reclen; 3308 cur_bytes += dirp->d_reclen; 3309 dirslot++; 3310 } 3311 addr = erraddr; 3312 cur_dir = addr; 3313 cur_bytes = errcur_bytes; 3314 stringsize = STRINGSIZE(dirp); 3315 dirslot--; 3316 if (tcount >= 0 && !star) { 3317 switch (type) { 3318 case FRAGMENT: 3319 printf("end of fragment\n"); 3320 break; 3321 case BLOCK: 3322 printf("end of block\n"); 3323 break; 3324 default: 3325 printf("end of directory\n"); 3326 } 3327 error++; 3328 } else 3329 error = 0; 3330 return; 3331 3332 case 'i': /* print as inodes */ 3333 if ((ip = (struct dinode *)getblk(addr)) == 0) 3334 return; 3335 for (i=1; i < fs->fs_ncg; i++) 3336 if (addr < (cgimin(fs,i) << FRGSHIFT)) 3337 break; 3338 i--; 3339 offset /= INODE; 3340 temp = (addr - (cgimin(fs,i) << FRGSHIFT)) >> FRGSHIFT; 3341 temp = (i * fs->fs_ipg) + fragstoblks(fs,temp) * 3342 INOPB(fs) + offset; 3343 if (count + offset > INOPB(fs)) { 3344 tcount = INOPB(fs) - offset; 3345 if (!star) 3346 end++; 3347 } 3348 objsz = INODE; 3349 ip += offset; 3350 for (i=0; tcount--; ip++, temp++) { 3351 if ((mode = icheck(addr)) == 0) 3352 if (!override) 3353 continue; 3354 p = " ugtrwxrwxrwx"; 3355 3356 switch (mode & IFMT) { 3357 case IFDIR: 3358 c = 'd'; 3359 break; 3360 case IFCHR: 3361 c = 'c'; 3362 break; 3363 case IFBLK: 3364 c = 'b'; 3365 break; 3366 case IFREG: 3367 c = '-'; 3368 break; 3369 case IFLNK: 3370 c = 'l'; 3371 break; 3372 case IFSOCK: 3373 c = 's'; 3374 break; 3375 default: 3376 c = '?'; 3377 if (!override) 3378 goto empty; 3379 3380 } 3381 printf("i#: "); 3382 print(temp,12,-8,0); 3383 printf(" md: "); 3384 printf("%c", c); 3385 for (mode = mode << 4; *++p; mode = mode << 1) { 3386 if (mode & IFREG) 3387 printf("%c", *p); 3388 else 3389 printf("-"); 3390 } 3391 printf(" uid: "); 3392 print(ip->di_uid,8,-4,0); 3393 printf(" gid: "); 3394 print(ip->di_gid,8,-4,0); 3395 printf("\n"); 3396 printf("ln: "); 3397 print(ip->di_nlink,8,-4,0); 3398 printf(" bs: "); 3399 print(ip->di_blocks,12,-8,0); 3400 printf(" sz : "); 3401 print(ip->di_size,12,-8,0); 3402 printf("\n"); 3403 if (ip->di_mode & IFCHR) { 3404 printf("maj: "); 3405 print(ip->di_db[1] & 0377,4,-2,0); 3406 printf(" min: "); 3407 print(ip->di_db[0] & 0377,4,-2,0); 3408 printf("\n"); 3409 } else { 3410 for (i = 0; i < NDADDR; ) { 3411 if (ip->di_db[i] == 0) 3412 break; 3413 printf("db#%x: ",i); 3414 print(ip->di_db[i],11,-8,0); 3415 if (++i % 4 == 0) 3416 printf("\n"); 3417 else 3418 printf(" "); 3419 } 3420 if (i % 4) 3421 printf("\n"); 3422 for (i = 0; i < NIADDR; i++) { 3423 if (ip->di_ib[i] == 0) 3424 break; 3425 printf("ib#%x: ",i); 3426 print(ip->di_ib[i],11,-8,0); 3427 printf(" "); 3428 } 3429 if (i) 3430 printf("\n"); 3431 } 3432 if (count == 1) { 3433 printf("\taccessed: %s", 3434 ctime(&ip->di_atime)); 3435 printf("\tmodified: %s", 3436 ctime(&ip->di_mtime)); 3437 printf("\tcreated : %s", 3438 ctime(&ip->di_ctime)); 3439 } 3440 if (tcount) 3441 printf("\n"); 3442 empty: 3443 if (c == '?' && !override) { 3444 printf("i#: "); 3445 print(temp, 12, -8, 0); 3446 printf(" is unallocated\n"); 3447 if (count != 1) 3448 printf("\n"); 3449 } 3450 cur_ino = erraddr = addr; 3451 errcur_bytes = cur_bytes; 3452 cur_inum++; 3453 addr = addr + INODE; 3454 } 3455 addr = erraddr; 3456 cur_bytes = errcur_bytes; 3457 cur_inum--; 3458 if (end) { 3459 printf("end of block\n"); 3460 error++; 3461 } 3462 return; 3463 3464 case 's': /* print as super block */ 3465 if (cur_cgrp == -1) { 3466 addr = SBLOCK * DEV_BSIZE; 3467 type = NUMB; 3468 } 3469 addr &= ~(LONG - 1); 3470 if (type != NUMB) 3471 if (cur_cgrp + count > fs->fs_ncg) { 3472 tcount = fs->fs_ncg - cur_cgrp; 3473 if (!star) 3474 end++; 3475 } 3476 for (; tcount--;) { 3477 erraddr = addr; 3478 cur_bytes = errcur_bytes; 3479 if (type != NUMB) { 3480 addr = cgsblock(fs, cur_cgrp) 3481 << FRGSHIFT; 3482 cur_cgrp++; 3483 } 3484 if ((cptr = getblk(addr)) == 0) { 3485 if (cur_cgrp) 3486 cur_cgrp--; 3487 return; 3488 } 3489 cptr += blkoff(fs, addr); 3490 sb = (struct fs *)cptr; 3491 if (type == NUMB) { 3492 for (i = 0; i < fs->fs_ncg; i++) 3493 if (addr == cgsblock(fs, i) << 3494 FRGSHIFT) 3495 break; 3496 if (i == fs->fs_ncg) 3497 cur_cgrp = 0; 3498 else 3499 cur_cgrp = i + 1; 3500 type = objsz = SB; 3501 if (cur_cgrp + count - 1 > fs->fs_ncg) { 3502 tcount = fs->fs_ncg - cur_cgrp; 3503 if (!star) 3504 end++; 3505 } 3506 } 3507 if (sb->fs_magic != FS_MAGIC) { 3508 cur_cgrp = 0; 3509 if (!override) { 3510 printf("invalid super block "); 3511 printf("magic word\n"); 3512 cur_cgrp--; 3513 error++; 3514 return; 3515 } 3516 } 3517 if (cur_cgrp == 0) 3518 printf("\tsuper block:\n"); 3519 else { 3520 printf("\tsuper block in cylinder "); 3521 printf("group "); 3522 print(cur_cgrp - 1, 0, 0, 0); 3523 printf(":\n"); 3524 } 3525 printsb(sb); 3526 if (tcount) 3527 printf("\n"); 3528 } 3529 cur_cgrp--; 3530 if (end) { 3531 printf("end of super blocks\n"); 3532 error++; 3533 } 3534 return; 3535 default: 3536 error++; 3537 printf("no such print option\n"); 3538 return; 3539 } 3540 } 3541 3542 /* 3543 * valid_addr - call check_addr to validate the current address. 3544 */ 3545 valid_addr() 3546 { 3547 short eof_flag, end = 0, eof = 0; 3548 long tcount = count; 3549 3550 if (!trapped) 3551 return(1); 3552 if (cur_bytes < 0) { 3553 cur_bytes = 0; 3554 if (blocksize > filesize) { 3555 printf("beginning of file\n"); 3556 } else { 3557 if (type == BLOCK) 3558 printf("beginning of block\n"); 3559 else 3560 printf("beginning of fragment\n"); 3561 } 3562 error++; 3563 return(0); 3564 } 3565 count = 1; 3566 check_addr(1, &end, &eof, (filesize < blocksize)); 3567 count = tcount; 3568 if (eof) { 3569 printf("end of file\n"); 3570 error++; 3571 return(0); 3572 } 3573 if (end == 2) { 3574 if (erraddr > addr) { 3575 if (type == BLOCK) 3576 printf("beginning of block\n"); 3577 else 3578 printf("beginning of fragment\n"); 3579 error++; 3580 return(0); 3581 } 3582 } 3583 if (end) { 3584 if (type == BLOCK) 3585 printf("end of block\n"); 3586 else 3587 printf("end of fragment\n"); 3588 error++; 3589 return(0); 3590 } 3591 return(1); 3592 } 3593 3594 /* 3595 * check_addr - check if the address crosses the end of block or 3596 * end of file. Return the proper count. 3597 */ 3598 check_addr(eof_flag, end, eof, keep_on) 3599 short eof_flag, *end, *eof, keep_on; 3600 { 3601 long temp, tcount = count, taddr = addr, tcur_bytes = cur_bytes; 3602 3603 if (bcomp(addr + count * objsz - 1) || 3604 (keep_on && taddr < (bmap(cur_block) << FRGSHIFT))) { 3605 error = 0; 3606 addr = taddr; 3607 cur_bytes = tcur_bytes; 3608 if (keep_on) { 3609 if (addr < erraddr) { 3610 if (cur_bytes < 0) { 3611 (*end) = 2; 3612 return; 3613 } 3614 temp = cur_block - lblkno(fs, cur_bytes); 3615 cur_block -= temp; 3616 if ((addr = bmap(cur_block) << FRGSHIFT) == 0) { 3617 cur_block += temp; 3618 return; 3619 } 3620 temp = tcur_bytes - cur_bytes; 3621 addr += temp; 3622 cur_bytes += temp; 3623 return; 3624 } else { 3625 if (cur_bytes >= filesize) { 3626 (*eof)++; 3627 return; 3628 } 3629 temp = lblkno(fs, cur_bytes) - cur_block; 3630 cur_block += temp; 3631 if ((addr = bmap(cur_block) << FRGSHIFT) == 0) { 3632 cur_block -= temp; 3633 return; 3634 } 3635 temp = tcur_bytes - cur_bytes; 3636 addr += temp; 3637 cur_bytes += temp; 3638 return; 3639 } 3640 } 3641 tcount = (blkroundup(fs, addr+1)-addr) / objsz; 3642 if (!star) 3643 (*end) = 2; 3644 } 3645 addr = taddr; 3646 cur_bytes = tcur_bytes; 3647 if (eof_flag) { 3648 if (blocksize > filesize) { 3649 if (cur_bytes >= filesize) { 3650 tcount = 0; 3651 (*eof)++; 3652 } else if (tcount > (filesize - cur_bytes) / objsz) { 3653 tcount = (filesize - cur_bytes) / objsz; 3654 if (!star || tcount == 0) 3655 (*eof)++; 3656 } 3657 } else { 3658 if (cur_bytes >= blocksize) { 3659 tcount = 0; 3660 (*end)++; 3661 } else if (tcount > (blocksize - cur_bytes) / objsz) { 3662 tcount = (blocksize - cur_bytes) / objsz; 3663 if (!star || tcount == 0) 3664 (*end)++; 3665 } 3666 } 3667 } 3668 return(tcount); 3669 } 3670 3671 /* 3672 * print_check - check if the index needs to be printed and delete 3673 * rows of zeros from the output. 3674 */ 3675 unsigned long * 3676 print_check(lptr, tcount, tbase, i) 3677 unsigned long *lptr; 3678 long *tcount; 3679 short tbase; 3680 register int i; 3681 { 3682 register int j, k, temp = BYTESPERLINE / objsz; 3683 short first_time = 0; 3684 unsigned long *tlptr; 3685 unsigned short *tsptr, *sptr; 3686 3687 sptr = (unsigned short *)lptr; 3688 if (i == 0) 3689 first_time = 1; 3690 if (i % temp == 0) { 3691 if (*tcount >= temp - 1) { 3692 if (objsz == SHORT) 3693 tsptr = sptr; 3694 else 3695 tlptr = lptr; 3696 k = *tcount - 1; 3697 for (j = i; k--; j++) 3698 if (objsz == SHORT) { 3699 if (*tsptr++ != 0) 3700 break; 3701 } else { 3702 if (*tlptr++ != 0) 3703 break; 3704 } 3705 if (j > (i + temp - 1)) { 3706 j = (j - i) / temp; 3707 while (j-- > 0) { 3708 if (objsz == SHORT) 3709 sptr += temp; 3710 else 3711 lptr += temp; 3712 *tcount -= temp; 3713 i += temp; 3714 addr += BYTESPERLINE; 3715 cur_bytes += BYTESPERLINE; 3716 } 3717 if (first_time) 3718 printf("*"); 3719 else 3720 printf("\n*"); 3721 } 3722 if (i) 3723 printf("\n"); 3724 index(tbase); 3725 } else { 3726 if (i) 3727 printf("\n"); 3728 index(tbase); 3729 } 3730 } 3731 if(objsz == SHORT) 3732 return((unsigned long *)sptr); 3733 else 3734 return(lptr); 3735 } 3736 3737 /* 3738 * index - print a byte index for the printout in base b 3739 * with leading zeros. 3740 */ 3741 index(b) 3742 int b; 3743 { 3744 int tbase = base; 3745 3746 base = b; 3747 print(addr, 8, 8, 1); 3748 printf(":\t"); 3749 base = tbase; 3750 } 3751 3752 /* 3753 * print - print out the value to digits places with/without 3754 * leading zeros and right/left justified in the current base. 3755 */ 3756 print(value, fieldsz, digits, lead) 3757 int value, fieldsz, digits, lead; 3758 { 3759 register int i, left = 0; 3760 char mode = BASE[base - OCTAL]; 3761 char *string = &scratch[0]; 3762 3763 if (digits < 0) { 3764 left = 1; 3765 digits *= -1; 3766 } 3767 if (base != HEX) 3768 if (digits) 3769 digits = digits + (digits - 1)/((base >> 1) - 1) + 1; 3770 else 3771 digits = 1; 3772 if (lead) { 3773 if (left) 3774 sprintf(string, "%%%c%d%d.%d%c", 3775 '-', 0, digits, lead, mode); 3776 else 3777 sprintf(string, "%%%d%d.%d%c", 0, digits, lead, mode); 3778 } else { 3779 if (left) 3780 sprintf(string, "%%%c%d%c", '-', digits, mode); 3781 else 3782 sprintf(string, "%%%d%c", digits, mode); 3783 } 3784 printf(string, value); 3785 for (i = 0; i < fieldsz - digits; i++) 3786 printf(" "); 3787 } 3788 3789 /* 3790 * Print out the contents of a superblock. 3791 */ 3792 printsb(fs) 3793 struct fs *fs; 3794 { 3795 int c, i, j, k, size; 3796 3797 #ifdef FS_42POSTBLFMT 3798 if (fs->fs_postblformat == FS_42POSTBLFMT) 3799 fs->fs_nrpos = 8; 3800 printf("magic\t%x\tformat\t%s\ttime\t%s", fs->fs_magic, 3801 fs->fs_postblformat == FS_42POSTBLFMT ? "static" : "dynamic", 3802 ctime(&fs->fs_time)); 3803 #else 3804 printf("magic\t%x\ttime\t%s", 3805 fs->fs_magic, ctime(&fs->fs_time)); 3806 #endif 3807 printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n", 3808 fs->fs_cstotal.cs_nbfree, fs->fs_cstotal.cs_ndir, 3809 fs->fs_cstotal.cs_nifree, fs->fs_cstotal.cs_nffree); 3810 printf("ncg\t%d\tncyl\t%d\tsize\t%d\tblocks\t%d\n", 3811 fs->fs_ncg, fs->fs_ncyl, fs->fs_size, fs->fs_dsize); 3812 printf("bsize\t%d\tshift\t%d\tmask\t0x%08x\n", 3813 fs->fs_bsize, fs->fs_bshift, fs->fs_bmask); 3814 printf("fsize\t%d\tshift\t%d\tmask\t0x%08x\n", 3815 fs->fs_fsize, fs->fs_fshift, fs->fs_fmask); 3816 printf("frag\t%d\tshift\t%d\tfsbtodb\t%d\n", 3817 fs->fs_frag, fs->fs_fragshift, fs->fs_fsbtodb); 3818 printf("cpg\t%d\tbpg\t%d\tfpg\t%d\tipg\t%d\n", 3819 fs->fs_cpg, fs->fs_fpg / fs->fs_frag, fs->fs_fpg, fs->fs_ipg); 3820 printf("minfree\t%d%%\toptim\t%s\tmaxcontig %d\tmaxbpg\t%d\n", 3821 fs->fs_minfree, fs->fs_optim == FS_OPTSPACE ? "space" : "time", 3822 fs->fs_maxcontig, fs->fs_maxbpg); 3823 #ifdef FS_42POSTBLFMT 3824 printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n", 3825 fs->fs_rotdelay, fs->fs_headswitch, fs->fs_trkseek, fs->fs_rps); 3826 printf("ntrak\t%d\tnsect\t%d\tnpsect\t%d\tspc\t%d\n", 3827 fs->fs_ntrak, fs->fs_nsect, fs->fs_npsect, fs->fs_spc); 3828 printf("trackskew %d\tinterleave %d\n", 3829 fs->fs_trackskew, fs->fs_interleave); 3830 #else 3831 printf("rotdelay %dms\trps\t%d\n", 3832 fs->fs_rotdelay, fs->fs_rps); 3833 printf("ntrak\t%d\tnsect\t%d\tspc\t%d\n", 3834 fs->fs_ntrak, fs->fs_nsect, fs->fs_spc); 3835 #endif 3836 printf("nindir\t%d\tinopb\t%d\tnspf\t%d\n", 3837 fs->fs_nindir, fs->fs_inopb, fs->fs_nspf); 3838 printf("sblkno\t%d\tcblkno\t%d\tiblkno\t%d\tdblkno\t%d\n", 3839 fs->fs_sblkno, fs->fs_cblkno, fs->fs_iblkno, fs->fs_dblkno); 3840 printf("sbsize\t%d\tcgsize\t%d\tcgoffset %d\tcgmask\t0x%08x\n", 3841 fs->fs_sbsize, fs->fs_cgsize, fs->fs_cgoffset, fs->fs_cgmask); 3842 printf("csaddr\t%d\tcssize\t%d\tshift\t%d\tmask\t0x%08x\n", 3843 fs->fs_csaddr, fs->fs_cssize, fs->fs_csshift, fs->fs_csmask); 3844 printf("cgrotor\t%d\tfmod\t%d\tronly\t%d\n", 3845 fs->fs_cgrotor, fs->fs_fmod, fs->fs_ronly); 3846 #ifdef FS_42POSTBLFMT 3847 if (fs->fs_cpc != 0) 3848 printf("blocks available in each of %d rotational positions", 3849 fs->fs_nrpos); 3850 else 3851 printf("insufficient space to maintain rotational tables\n"); 3852 #endif 3853 for (c = 0; c < fs->fs_cpc; c++) { 3854 printf("\ncylinder number %d:", c); 3855 #ifdef FS_42POSTBLFMT 3856 for (i = 0; i < fs->fs_nrpos; i++) { 3857 if (fs_postbl(fs, c)[i] == -1) 3858 continue; 3859 printf("\n position %d:\t", i); 3860 for (j = fs_postbl(fs, c)[i], k = 1; ; 3861 j += fs_rotbl(fs)[j], k++) { 3862 printf("%5d", j); 3863 if (k % 12 == 0) 3864 printf("\n\t\t"); 3865 if (fs_rotbl(fs)[j] == 0) 3866 break; 3867 } 3868 } 3869 #else 3870 for (i = 0; i < NRPOS; i++) { 3871 if (fs->fs_postbl[c][i] == -1) 3872 continue; 3873 printf("\n position %d:\t", i); 3874 for (j = fs->fs_postbl[c][i], k = 1; ; 3875 j += fs->fs_rotbl[j], k++) { 3876 printf("%5d", j); 3877 if (k % 12 == 0) 3878 printf("\n\t\t"); 3879 if (fs->fs_rotbl[j] == 0) 3880 break; 3881 } 3882 } 3883 #endif 3884 } 3885 printf("\ncs[].cs_(nbfree,ndir,nifree,nffree):\n\t"); 3886 for (i = 0, j = 0; i < fs->fs_cssize; i += fs->fs_bsize, j++) { 3887 size = fs->fs_cssize - i < fs->fs_bsize ? 3888 fs->fs_cssize - i : fs->fs_bsize; 3889 fs->fs_csp[j] = (struct csum *)calloc(1, size); 3890 lseek(fd, fsbtodb(fs, (fs->fs_csaddr + j * fs->fs_frag)) * 3891 fs->fs_fsize / fsbtodb(fs, 1), 0); 3892 if (read(fd, fs->fs_csp[j], size) != size) { 3893 for (j--; j >= 0; j--) 3894 free(fs->fs_csp[j]); 3895 return; 3896 } 3897 } 3898 for (i = 0; i < fs->fs_ncg; i++) { 3899 struct csum *cs = &fs->fs_cs(fs, i); 3900 if (i && i % 4 == 0) 3901 printf("\n\t"); 3902 printf("(%d,%d,%d,%d) ", 3903 cs->cs_nbfree, cs->cs_ndir, cs->cs_nifree, cs->cs_nffree); 3904 } 3905 for (j--; j >= 0; j--) 3906 free(fs->fs_csp[j]); 3907 printf("\n"); 3908 if (fs->fs_ncyl % fs->fs_cpg) { 3909 printf("cylinders in last group %d\n", 3910 i = fs->fs_ncyl % fs->fs_cpg); 3911 printf("blocks in last group %d\n", 3912 i * fs->fs_spc / NSPB(fs)); 3913 } 3914 } 3915 3916 /* 3917 * Print out the contents of a cylinder group. 3918 */ 3919 printcg(cg) 3920 struct cg *cg; 3921 { 3922 int i,j; 3923 3924 printf("\ncg %d:\n", cg->cg_cgx); 3925 #ifdef FS_42POSTBLFMT 3926 printf("magic\t%x\ttell\t%x\ttime\t%s", 3927 fs->fs_postblformat == FS_42POSTBLFMT ? 3928 ((struct ocg *)cg)->cg_magic : cg->cg_magic, 3929 fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1), 3930 ctime(&cg->cg_time)); 3931 #else 3932 printf("magic\t%x\ttell\t%x\ttime\t%s", 3933 cg->cg_magic, 3934 fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1), 3935 ctime(&cg->cg_time)); 3936 #endif 3937 printf("cgx\t%d\tncyl\t%d\tniblk\t%d\tndblk\t%d\n", 3938 cg->cg_cgx, cg->cg_ncyl, cg->cg_niblk, cg->cg_ndblk); 3939 printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n", 3940 cg->cg_cs.cs_nbfree, cg->cg_cs.cs_ndir, 3941 cg->cg_cs.cs_nifree, cg->cg_cs.cs_nffree); 3942 printf("rotor\t%d\tirotor\t%d\tfrotor\t%d\nfrsum", 3943 cg->cg_rotor, cg->cg_irotor, cg->cg_frotor); 3944 for (i = 1, j = 0; i < fs->fs_frag; i++) { 3945 printf("\t%d", cg->cg_frsum[i]); 3946 j += i * cg->cg_frsum[i]; 3947 } 3948 printf("\nsum of frsum: %d\niused:\t", j); 3949 pbits(cg_inosused(cg), fs->fs_ipg); 3950 printf("free:\t"); 3951 pbits(cg_blksfree(cg), fs->fs_fpg); 3952 printf("b:\n"); 3953 for (i = 0; i < fs->fs_cpg; i++) { 3954 if (cg_blktot(cg)[i] == 0) 3955 continue; 3956 printf(" c%d:\t(%d)\t", i, cg_blktot(cg)[i]); 3957 #ifdef FS_42POSTBLFMT 3958 for (j = 0; j < fs->fs_nrpos; j++) { 3959 if (fs->fs_cpc == 0 || 3960 fs_postbl(fs, i % fs->fs_cpc)[j] == -1) 3961 continue; 3962 printf(" %d", cg_blks(fs, cg, i)[j]); 3963 } 3964 #else 3965 for (j = 0; j < NRPOS; j++) { 3966 if (fs->fs_cpc == 0 || 3967 fs->fs_postbl[i % fs->fs_cpc][j] == -1) 3968 continue; 3969 printf(" %d", cg->cg_b[i][j]); 3970 } 3971 #endif 3972 printf("\n"); 3973 } 3974 } 3975 3976 /* 3977 * Print out the contents of a bit array. 3978 */ 3979 pbits(cp, max) 3980 register char *cp; 3981 int max; 3982 { 3983 register int i; 3984 int count = 0, j; 3985 3986 for (i = 0; i < max; i++) 3987 if (isset(cp, i)) { 3988 if (count) 3989 printf(",%s", count % 6 ? " " : "\n\t"); 3990 count++; 3991 printf("%d", i); 3992 j = i; 3993 while ((i+1)<max && isset(cp, i+1)) 3994 i++; 3995 if (i != j) 3996 printf("-%d", i); 3997 } 3998 printf("\n"); 3999 } 4000 4001 /* 4002 * bcomp - used to check for block over/under flows when stepping through 4003 * a file system. 4004 */ 4005 bcomp(addr) 4006 long addr; 4007 { 4008 if (override) 4009 return(0); 4010 if (lblkno(fs, addr) == (bhdr.fwd)->blkno) 4011 return(0); 4012 error++; 4013 return(1); 4014 } 4015 4016 /* 4017 * bmap - maps the logical block number of a file into 4018 * the corresponding physical block on the file 4019 * system. 4020 */ 4021 long 4022 bmap(bn) 4023 long bn; 4024 { 4025 register int i, j; 4026 register struct dinode *ip; 4027 int sh; 4028 long nb; 4029 4030 ip = (struct dinode *)cur_ino; 4031 if (bn < NDADDR) { 4032 addr = (long)&ip->di_db[bn]; 4033 cur_bytes = bn * BLKSIZE; 4034 return(nullblk(nb=get(LONG)) ? 0L : nb); 4035 } 4036 4037 sh = 1; 4038 bn -= NDADDR; 4039 for (j = NIADDR; j > 0; j--) { 4040 sh *= NINDIR(fs); 4041 if (bn < sh) 4042 break; 4043 bn -= sh; 4044 } 4045 if (j == 0) { 4046 printf("file too big\n"); 4047 error++; 4048 return(0L); 4049 } 4050 addr = (long)&ip->di_ib[NIADDR - j]; 4051 nb = get(LONG); 4052 if (nb == 0) 4053 return(0L); 4054 for (; j <= NIADDR; j++) { 4055 sh /= NINDIR(fs); 4056 addr = (nb << FRGSHIFT) + ((bn / sh) % NINDIR(fs)) * LONG; 4057 if (nullblk(nb = get(LONG))) 4058 return(0L); 4059 } 4060 return(nb); 4061 } 4062