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