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