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