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