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