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