1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Copyright (c) 1988 Regents of the University of California. 10 * All rights reserved. 11 * 12 * This code is derived from software contributed to Berkeley by 13 * Computer Consoles Inc. 14 * 15 * Redistribution and use in source and binary forms are permitted 16 * provided that: (1) source distributions retain this entire copyright 17 * notice and comment, and (2) distributions including binaries display 18 * the following acknowledgement: ``This product includes software 19 * developed by the University of California, Berkeley and its contributors'' 20 * in the documentation or other materials provided with the distribution 21 * and in all advertising materials mentioning features or use of this 22 * software. Neither the name of the University nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 28 */ 29 30 #ifndef lint 31 char copyright[] = 32 "@(#) Copyright(c) 1988 Regents of the University of California.\n\ 33 All rights reserved.\n"; 34 #endif /* not lint */ 35 36 #ifndef lint 37 static char sccsid[] = "@(#)fsdb.c 5.8 (Berkeley) 6/1/90"; 38 #endif /* not lint */ 39 40 /* 41 * fsdb - file system debugger 42 * 43 * usage: fsdb [-o suboptions] special 44 * options/suboptions: 45 * -o 46 * ? display usage 47 * o override some error conditions 48 * p="string" set prompt to string 49 * w open for write 50 */ 51 52 #include <sys/param.h> 53 #include <sys/signal.h> 54 #include <sys/file.h> 55 #include <inttypes.h> 56 #include <sys/sysmacros.h> 57 58 #ifdef sun 59 #include <unistd.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <fcntl.h> 63 #include <signal.h> 64 #include <sys/types.h> 65 #include <sys/vnode.h> 66 #include <sys/mntent.h> 67 #include <sys/wait.h> 68 #include <sys/fs/ufs_fsdir.h> 69 #include <sys/fs/ufs_fs.h> 70 #include <sys/fs/ufs_inode.h> 71 #include <sys/fs/ufs_acl.h> 72 #include <sys/fs/ufs_log.h> 73 #else 74 #include <sys/dir.h> 75 #include <ufs/fs.h> 76 #include <ufs/dinode.h> 77 #include <paths.h> 78 #endif /* sun */ 79 80 #include <stdio.h> 81 #include <setjmp.h> 82 83 #define OLD_FSDB_COMPATIBILITY /* To support the obsoleted "-z" option */ 84 85 #ifndef _PATH_BSHELL 86 #define _PATH_BSHELL "/bin/sh" 87 #endif /* _PATH_BSHELL */ 88 /* 89 * Defines from the 4.3-tahoe file system, for systems with the 4.2 or 4.3 90 * file system. 91 */ 92 #ifndef FS_42POSTBLFMT 93 #define cg_blktot(cgp) (((cgp))->cg_btot) 94 #define cg_blks(fs, cgp, cylno) (((cgp))->cg_b[cylno]) 95 #define cg_inosused(cgp) (((cgp))->cg_iused) 96 #define cg_blksfree(cgp) (((cgp))->cg_free) 97 #define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC) 98 #endif 99 100 /* 101 * Never changing defines. 102 */ 103 #define OCTAL 8 /* octal base */ 104 #define DECIMAL 10 /* decimal base */ 105 #define HEX 16 /* hexadecimal base */ 106 107 /* 108 * Adjustable defines. 109 */ 110 #define NBUF 10 /* number of cache buffers */ 111 #define PROMPTSIZE 80 /* size of user definable prompt */ 112 #define MAXFILES 40000 /* max number of files ls can handle */ 113 #define FIRST_DEPTH 10 /* default depth for find and ls */ 114 #define SECOND_DEPTH 100 /* second try at depth (maximum) */ 115 #define INPUTBUFFER 1040 /* size of input buffer */ 116 #define BYTESPERLINE 16 /* bytes per line of /dxo output */ 117 #define NREG 36 /* number of save registers */ 118 119 #define DEVPREFIX "/dev/" /* Uninteresting part of "special" */ 120 121 #if defined(OLD_FSDB_COMPATIBILITY) 122 #define FSDB_OPTIONS "o:wp:z:" 123 #else 124 #define FSDB_OPTIONS "o:wp:" 125 #endif /* OLD_FSDB_COMPATIBILITY */ 126 127 128 /* 129 * Values dependent on sizes of structs and such. 130 */ 131 #define NUMB 3 /* these three are arbitrary, */ 132 #define BLOCK 5 /* but must be different from */ 133 #define FRAGMENT 7 /* the rest (hence odd). */ 134 #define BITSPERCHAR 8 /* couldn't find it anywhere */ 135 #define CHAR (sizeof (char)) 136 #define SHORT (sizeof (short)) 137 #define LONG (sizeof (long)) 138 #define U_OFFSET_T (sizeof (u_offset_t)) /* essentially "long long" */ 139 #define INODE (sizeof (struct dinode)) 140 #define DIRECTORY (sizeof (struct direct)) 141 #define CGRP (sizeof (struct cg)) 142 #define SB (sizeof (struct fs)) 143 #define BLKSIZE (fs->fs_bsize) /* for clarity */ 144 #define FRGSIZE (fs->fs_fsize) 145 #define BLKSHIFT (fs->fs_bshift) 146 #define FRGSHIFT (fs->fs_fshift) 147 #define SHADOW_DATA (sizeof (struct ufs_fsd)) 148 149 /* 150 * Messy macros that would otherwise clutter up such glamorous code. 151 */ 152 #define itob(i) (((u_offset_t)itod(fs, (i)) << \ 153 (u_offset_t)FRGSHIFT) + (u_offset_t)itoo(fs, (i)) * (u_offset_t)INODE) 154 #define min(x, y) ((x) < (y) ? (x) : (y)) 155 #define STRINGSIZE(d) ((long)d->d_reclen - \ 156 ((long)&d->d_name[0] - (long)&d->d_ino)) 157 #define letter(c) ((((c) >= 'a')&&((c) <= 'z')) ||\ 158 (((c) >= 'A')&&((c) <= 'Z'))) 159 #define digit(c) (((c) >= '0') && ((c) <= '9')) 160 #define HEXLETTER(c) (((c) >= 'A') && ((c) <= 'F')) 161 #define hexletter(c) (((c) >= 'a') && ((c) <= 'f')) 162 #define octaldigit(c) (((c) >= '0') && ((c) <= '7')) 163 #define uppertolower(c) ((c) - 'A' + 'a') 164 #define hextodigit(c) ((c) - 'a' + 10) 165 #define numtodigit(c) ((c) - '0') 166 167 #if !defined(loword) 168 #define loword(X) (((ushort_t *)&X)[1]) 169 #endif /* loword */ 170 171 #if !defined(lobyte) 172 #define lobyte(X) (((unsigned char *)&X)[1]) 173 #endif /* lobyte */ 174 175 /* 176 * buffer cache structure. 177 */ 178 static struct lbuf { 179 struct lbuf *fwd; 180 struct lbuf *back; 181 char *blkaddr; 182 short valid; 183 u_offset_t blkno; 184 } lbuf[NBUF], bhdr; 185 186 /* 187 * used to hold save registers (see '<' and '>'). 188 */ 189 struct save_registers { 190 u_offset_t sv_addr; 191 u_offset_t sv_value; 192 long sv_objsz; 193 } regs[NREG]; 194 195 /* 196 * cd, find, and ls use this to hold filenames. Each filename is broken 197 * up by a slash. In other words, /usr/src/adm would have a len field 198 * of 2 (starting from 0), and filenames->fname[0-2] would hold usr, 199 * src, and adm components of the pathname. 200 */ 201 static struct filenames { 202 ino_t ino; /* inode */ 203 long len; /* number of components */ 204 char flag; /* flag if using SECOND_DEPTH allocator */ 205 char find; /* flag if found by find */ 206 char **fname; /* hold components of pathname */ 207 } *filenames, *top; 208 209 enum log_enum { LOG_NDELTAS, LOG_ALLDELTAS, LOG_CHECKSCAN }; 210 #ifdef sun 211 struct fs *fs; 212 static union { 213 struct fs un_filesystem; 214 char un_sbsize[SBSIZE]; 215 } fs_un; 216 #define filesystem fs_un.un_filesystem 217 #else 218 struct fs filesystem, *fs; /* super block */ 219 #endif /* sun */ 220 221 /* 222 * Global data. 223 */ 224 static char *input_path[MAXPATHLEN]; 225 static char *stack_path[MAXPATHLEN]; 226 static char *current_path[MAXPATHLEN]; 227 static char input_buffer[INPUTBUFFER]; 228 static char *prompt; 229 static char *buffers; 230 static char scratch[64]; 231 static char BASE[] = "o u x"; 232 static char PROMPT[PROMPTSIZE]; 233 static char laststyle = '/'; 234 static char lastpo = 'x'; 235 static short input_pointer; 236 static short current_pathp; 237 static short stack_pathp; 238 static short input_pathp; 239 static short cmp_level; 240 static int nfiles; 241 static short type = NUMB; 242 static short dirslot; 243 static short fd; 244 static short c_count; 245 static short error; 246 static short paren; 247 static short trapped; 248 static short doing_cd; 249 static short doing_find; 250 static short find_by_name; 251 static short find_by_inode; 252 static short long_list; 253 static short recursive; 254 static short objsz = SHORT; 255 static short override = 0; 256 static short wrtflag = O_RDONLY; 257 static short base = HEX; 258 static short acting_on_inode; 259 static short acting_on_directory; 260 static short should_print = 1; 261 static short clear; 262 static short star; 263 static u_offset_t addr; 264 static u_offset_t bod_addr; 265 static u_offset_t value; 266 static u_offset_t erraddr; 267 static long errcur_bytes; 268 static u_offset_t errino; 269 static long errinum; 270 static long cur_cgrp; 271 static u_offset_t cur_ino; 272 static long cur_inum; 273 static u_offset_t cur_dir; 274 static long cur_block; 275 static long cur_bytes; 276 static long find_ino; 277 static u_offset_t filesize; 278 static u_offset_t blocksize; 279 static long stringsize; 280 static long count = 1; 281 static long commands; 282 static long read_requests; 283 static long actual_disk_reads; 284 static jmp_buf env; 285 static long maxfiles; 286 static long cur_shad; 287 288 #ifndef sun 289 extern char *malloc(), *calloc(); 290 #endif 291 static char getachar(); 292 static char *getblk(), *fmtentry(); 293 294 static offset_t get(); 295 static long bmap(); 296 static long expr(); 297 static long term(); 298 static long getnumb(); 299 static u_offset_t getdirslot(); 300 static unsigned long *print_check(); 301 302 static void usage(); 303 static void ungetachar(); 304 static void getnextinput(); 305 static void eat_spaces(); 306 static void restore_inode(); 307 static void find(); 308 static void ls(); 309 static void formatf(); 310 static void parse(); 311 static void follow_path(); 312 static void getname(); 313 static void freemem(); 314 static void print_path(); 315 static void fill(); 316 static void put(); 317 static void insert(); 318 static void puta(); 319 static void fprnt(); 320 static void index(); 321 #ifdef _LARGEFILE64_SOURCE 322 static void printll 323 (u_offset_t value, int fieldsz, int digits, int lead); 324 #define print(value, fieldsz, digits, lead) \ 325 printll((u_offset_t)value, fieldsz, digits, lead) 326 #else /* !_LARGEFILE64_SOURCE */ 327 static void print(long value, int fieldsz, int digits, int lead); 328 #endif /* _LARGEFILE64_SOURCE */ 329 static void printsb(); 330 static void printcg(); 331 static void pbits(); 332 static void old_fsdb(); /* Support for old fsdb functionality */ 333 334 static int isnumber(); 335 static int icheck(); 336 static int cgrp_check(); 337 static int valid_addr(); 338 static int match(); 339 static int devcheck(); 340 static int bcomp(); 341 static int compare(); 342 static int check_addr(); 343 static int fcmp(); 344 static int ffcmp(); 345 346 static int getshadowslot(); 347 static void getshadowdata(); 348 static void syncshadowscan(); 349 350 #ifdef sun 351 static void err(); 352 #else 353 static int err(); 354 #endif /* sun */ 355 356 /* Suboption vector */ 357 static char *subopt_v[] = { 358 #define OVERRIDE 0 359 "o", 360 #define NEW_PROMPT 1 361 "p", 362 #define WRITE_ENABLED 2 363 "w", 364 #define ALT_PROMPT 3 365 "prompt", 366 NULL 367 }; 368 369 /* 370 * main - lines are read up to the unprotected ('\') newline and 371 * held in an input buffer. Characters may be read from the 372 * input buffer using getachar() and unread using ungetachar(). 373 * Reading the whole line ahead allows the use of debuggers 374 * which would otherwise be impossible since the debugger 375 * and fsdb could not share stdin. 376 */ 377 378 void 379 main(argc, argv) 380 int argc; 381 char *argv[]; 382 { 383 384 register char c, *cptr; 385 register short i; 386 register struct direct *dirp; 387 register struct lbuf *bp; 388 char *progname; 389 short colon, mode; 390 long temp; 391 392 /* Options/Suboptions processing */ 393 int opt; 394 char *subopts; 395 char *optval; 396 397 /* 398 * The following are used to support the old fsdb functionality 399 * of clearing an inode. It's better to use 'clri'. 400 */ 401 int inum; /* Inode number to clear */ 402 char *special; 403 404 setbuf(stdin, NULL); 405 progname = argv[0]; 406 prompt = &PROMPT[0]; 407 /* 408 * Parse options. 409 */ 410 while ((opt = getopt(argc, argv, FSDB_OPTIONS)) != EOF) { 411 switch (opt) { 412 #if defined(OLD_FSDB_COMPATIBILITY) 413 case 'z': /* Hack - Better to use clri */ 414 (void) fprintf(stderr, "%s\n%s\n%s\n%s\n", 415 "Warning: The '-z' option of 'fsdb_ufs' has been declared obsolete", 416 "and may not be supported in a future version of Solaris.", 417 "While this functionality is currently still supported, the", 418 "recommended procedure to clear an inode is to use clri(1M)."); 419 if (isnumber(optarg)) { 420 inum = atoi(optarg); 421 special = argv[optind]; 422 /* Doesn't return */ 423 old_fsdb(inum, special); 424 } else { 425 usage(progname); 426 exit(31+1); 427 } 428 /* Should exit() before here */ 429 /*NOTREACHED*/ 430 #endif /* OLD_FSDB_COMPATIBILITY */ 431 case 'o': 432 /* UFS Specific Options */ 433 subopts = optarg; 434 while (*subopts != '\0') { 435 switch (getsubopt(&subopts, subopt_v, 436 &optval)) { 437 case OVERRIDE: 438 printf("error checking off\n"); 439 override = 1; 440 break; 441 442 /* 443 * Change the "-o prompt=foo" option to 444 * "-o p=foo" to match documentation. 445 * ALT_PROMPT continues support for the 446 * undocumented "-o prompt=foo" option so 447 * that we don't break anyone. 448 */ 449 case NEW_PROMPT: 450 case ALT_PROMPT: 451 if (optval == NULL) { 452 (void) fprintf(stderr, 453 "No prompt string\n"); 454 usage(progname); 455 } 456 (void) strncpy(PROMPT, optval, 457 PROMPTSIZE); 458 break; 459 460 case WRITE_ENABLED: 461 /* suitable for open */ 462 wrtflag = O_RDWR; 463 break; 464 465 default: 466 usage(progname); 467 /* Should exit here */ 468 } 469 } 470 break; 471 472 default: 473 usage(progname); 474 } 475 } 476 477 if ((argc - optind) != 1) { /* Should just have "special" left */ 478 usage(progname); 479 } 480 special = argv[optind]; 481 482 /* 483 * Unless it's already been set, the default prompt includes the 484 * name of the special device. 485 */ 486 if (*prompt == NULL) 487 (void) sprintf(prompt, "%s > ", special); 488 489 /* 490 * Attempt to open the special file. 491 */ 492 if ((fd = open(special, wrtflag)) < 0) { 493 perror(special); 494 exit(1); 495 } 496 /* 497 * Read in the super block and validate (not too picky). 498 */ 499 if (llseek(fd, (offset_t)(SBLOCK * DEV_BSIZE), 0) == -1) { 500 perror(special); 501 exit(1); 502 } 503 504 #ifdef sun 505 if (read(fd, &filesystem, SBSIZE) != SBSIZE) { 506 printf("%s: cannot read superblock\n", special); 507 exit(1); 508 } 509 #else 510 if (read(fd, &filesystem, sizeof (filesystem)) != sizeof (filesystem)) { 511 printf("%s: cannot read superblock\n", special); 512 exit(1); 513 } 514 #endif /* sun */ 515 516 fs = &filesystem; 517 if ((fs->fs_magic != FS_MAGIC) && (fs->fs_magic != MTB_UFS_MAGIC)) { 518 if (!override) { 519 printf("%s: Bad magic number in file system\n", 520 special); 521 exit(1); 522 } 523 524 printf("WARNING: Bad magic number in file system. "); 525 printf("Continue? (y/n): "); 526 (void) fflush(stdout); 527 if (gets(input_buffer) == NULL) { 528 exit(1); 529 } 530 531 if (*input_buffer != 'y' && *input_buffer != 'Y') { 532 exit(1); 533 } 534 } 535 536 if (fs->fs_magic == MTB_UFS_MAGIC && 537 (fs->fs_version > MTB_UFS_VERSION_1 || 538 fs->fs_version < MTB_UFS_VERSION_MIN)) { 539 if (!override) { 540 printf("%s: Unrecognized UFS version number: %d\n", 541 special, fs->fs_version); 542 exit(1); 543 } 544 545 printf("WARNING: Unrecognized UFS version number. "); 546 printf("Continue? (y/n): "); 547 (void) fflush(stdout); 548 if (gets(input_buffer) == NULL) { 549 exit(1); 550 } 551 552 if (*input_buffer != 'y' && *input_buffer != 'Y') { 553 exit(1); 554 } 555 } 556 #ifdef FS_42POSTBLFMT 557 if (fs->fs_postblformat == FS_42POSTBLFMT) 558 fs->fs_nrpos = 8; 559 #endif 560 printf("fsdb of %s %s -- last mounted on %s\n", 561 special, 562 (wrtflag == O_RDWR) ? "(Opened for write)" : "(Read only)", 563 &fs->fs_fsmnt[0]); 564 #ifdef sun 565 printf("fs_clean is currently set to "); 566 switch (fs->fs_clean) { 567 568 case FSACTIVE: 569 printf("FSACTIVE\n"); 570 break; 571 case FSCLEAN: 572 printf("FSCLEAN\n"); 573 break; 574 case FSSTABLE: 575 printf("FSSTABLE\n"); 576 break; 577 case FSBAD: 578 printf("FSBAD\n"); 579 break; 580 case FSSUSPEND: 581 printf("FSSUSPEND\n"); 582 break; 583 case FSLOG: 584 printf("FSLOG\n"); 585 break; 586 case FSFIX: 587 printf("FSFIX\n"); 588 if (!override) { 589 printf("%s: fsck may be running on this file system\n", 590 special); 591 exit(1); 592 } 593 594 printf("WARNING: fsck may be running on this file system. "); 595 printf("Continue? (y/n): "); 596 (void) fflush(stdout); 597 if (gets(input_buffer) == NULL) { 598 exit(1); 599 } 600 601 if (*input_buffer != 'y' && *input_buffer != 'Y') { 602 exit(1); 603 } 604 break; 605 default: 606 printf("an unknown value (0x%x)\n", fs->fs_clean); 607 break; 608 } 609 610 if (fs->fs_state == (FSOKAY - fs->fs_time)) { 611 printf("fs_state consistent (fs_clean CAN be trusted)\n"); 612 } else { 613 printf("fs_state inconsistent (fs_clean CAN'T trusted)\n"); 614 } 615 #endif /* sun */ 616 /* 617 * Malloc buffers and set up cache. 618 */ 619 buffers = malloc(NBUF * BLKSIZE); 620 bhdr.fwd = bhdr.back = &bhdr; 621 for (i = 0; i < NBUF; i++) { 622 bp = &lbuf[i]; 623 bp->blkaddr = buffers + (i * BLKSIZE); 624 bp->valid = 0; 625 insert(bp); 626 } 627 /* 628 * Malloc filenames structure. The space for the actual filenames 629 * is allocated as it needs it. We estimate the size based on the 630 * number of inodes(objects) in the filesystem and the number of 631 * directories. The number of directories are padded by 3 because 632 * each directory traversed during a "find" or "ls -R" needs 3 633 * entries. 634 */ 635 maxfiles = (long)((((u_offset_t)fs->fs_ncg * (u_offset_t)fs->fs_ipg) - 636 (u_offset_t)fs->fs_cstotal.cs_nifree) + 637 ((u_offset_t)fs->fs_cstotal.cs_ndir * (u_offset_t)3)); 638 639 filenames = (struct filenames *)calloc(maxfiles, 640 sizeof (struct filenames)); 641 if (filenames == NULL) { 642 /* 643 * If we could not allocate memory for all of files 644 * in the filesystem then, back off to the old fixed 645 * value. 646 */ 647 maxfiles = MAXFILES; 648 filenames = (struct filenames *)calloc(maxfiles, 649 sizeof (struct filenames)); 650 if (filenames == NULL) { 651 printf("out of memory\n"); 652 exit(1); 653 } 654 } 655 656 restore_inode(2); 657 /* 658 * Malloc a few filenames (needed by pwd for example). 659 */ 660 for (i = 0; i < MAXPATHLEN; i++) { 661 input_path[i] = calloc(1, MAXNAMLEN); 662 stack_path[i] = calloc(1, MAXNAMLEN); 663 current_path[i] = calloc(1, MAXNAMLEN); 664 if (current_path[i] == NULL) { 665 printf("out of memory\n"); 666 exit(1); 667 } 668 } 669 current_pathp = -1; 670 671 (void) signal(2, err); 672 (void) setjmp(env); 673 674 getnextinput(); 675 /* 676 * Main loop and case statement. If an error condition occurs 677 * initialization and recovery is attempted. 678 */ 679 for (;;) { 680 if (error) { 681 freemem(filenames, nfiles); 682 nfiles = 0; 683 c_count = 0; 684 count = 1; 685 star = 0; 686 error = 0; 687 paren = 0; 688 acting_on_inode = 0; 689 acting_on_directory = 0; 690 should_print = 1; 691 addr = erraddr; 692 cur_ino = errino; 693 cur_inum = errinum; 694 cur_bytes = errcur_bytes; 695 printf("?\n"); 696 getnextinput(); 697 if (error) 698 continue; 699 } 700 c_count++; 701 702 switch (c = getachar()) { 703 704 case '\n': /* command end */ 705 freemem(filenames, nfiles); 706 nfiles = 0; 707 if (should_print && laststyle == '=') { 708 ungetachar(c); 709 goto calc; 710 } 711 if (c_count == 1) { 712 clear = 0; 713 should_print = 1; 714 erraddr = addr; 715 errino = cur_ino; 716 errinum = cur_inum; 717 errcur_bytes = cur_bytes; 718 switch (objsz) { 719 case DIRECTORY: 720 if ((addr = getdirslot( 721 (long)dirslot+1)) == 0) 722 should_print = 0; 723 if (error) { 724 ungetachar(c); 725 continue; 726 } 727 break; 728 case INODE: 729 cur_inum++; 730 addr = itob(cur_inum); 731 if (!icheck(addr)) { 732 cur_inum--; 733 should_print = 0; 734 } 735 break; 736 case CGRP: 737 case SB: 738 cur_cgrp++; 739 addr = cgrp_check(cur_cgrp); 740 if (addr == 0) { 741 cur_cgrp--; 742 continue; 743 } 744 break; 745 case SHADOW_DATA: 746 if ((addr = getshadowslot( 747 (long)cur_shad + 1)) == 0) 748 should_print = 0; 749 if (error) { 750 ungetachar(c); 751 continue; 752 } 753 break; 754 default: 755 addr += objsz; 756 cur_bytes += objsz; 757 if (valid_addr() == 0) 758 continue; 759 } 760 } 761 if (type == NUMB) 762 trapped = 0; 763 if (should_print) 764 switch (objsz) { 765 case DIRECTORY: 766 fprnt('?', 'd'); 767 break; 768 case INODE: 769 fprnt('?', 'i'); 770 if (!error) 771 cur_ino = addr; 772 break; 773 case CGRP: 774 fprnt('?', 'c'); 775 break; 776 case SB: 777 fprnt('?', 's'); 778 break; 779 case SHADOW_DATA: 780 fprnt('?', 'S'); 781 break; 782 case CHAR: 783 case SHORT: 784 case LONG: 785 fprnt(laststyle, lastpo); 786 } 787 if (error) { 788 ungetachar(c); 789 continue; 790 } 791 c_count = colon = acting_on_inode = 0; 792 acting_on_directory = 0; 793 should_print = 1; 794 getnextinput(); 795 if (error) 796 continue; 797 erraddr = addr; 798 errino = cur_ino; 799 errinum = cur_inum; 800 errcur_bytes = cur_bytes; 801 continue; 802 803 case '(': /* numeric expression or unknown command */ 804 default: 805 colon = 0; 806 if (digit(c) || c == '(') { 807 ungetachar(c); 808 addr = expr(); 809 type = NUMB; 810 value = addr; 811 continue; 812 } 813 printf("unknown command or bad syntax\n"); 814 error++; 815 continue; 816 817 case '?': /* general print facilities */ 818 case '/': 819 fprnt(c, getachar()); 820 continue; 821 822 case ';': /* command separator and . */ 823 case '\t': 824 case ' ': 825 case '.': 826 continue; 827 828 case ':': /* command indicator */ 829 colon++; 830 commands++; 831 should_print = 0; 832 stringsize = 0; 833 trapped = 0; 834 continue; 835 836 case ',': /* count indicator */ 837 colon = star = 0; 838 if ((c = getachar()) == '*') { 839 star = 1; 840 count = BLKSIZE; 841 } else { 842 ungetachar(c); 843 count = expr(); 844 if (error) 845 continue; 846 if (!count) 847 count = 1; 848 } 849 clear = 0; 850 continue; 851 852 case '+': /* address addition */ 853 colon = 0; 854 c = getachar(); 855 ungetachar(c); 856 if (c == '\n') 857 temp = 1; 858 else { 859 temp = expr(); 860 if (error) 861 continue; 862 } 863 erraddr = addr; 864 errcur_bytes = cur_bytes; 865 switch (objsz) { 866 case DIRECTORY: 867 addr = getdirslot((long)(dirslot + temp)); 868 if (error) 869 continue; 870 break; 871 case INODE: 872 cur_inum += temp; 873 addr = itob(cur_inum); 874 if (!icheck(addr)) { 875 cur_inum -= temp; 876 continue; 877 } 878 break; 879 case CGRP: 880 case SB: 881 cur_cgrp += temp; 882 if ((addr = cgrp_check(cur_cgrp)) == 0) { 883 cur_cgrp -= temp; 884 continue; 885 } 886 break; 887 case SHADOW_DATA: 888 addr = getshadowslot((long)(cur_shad + temp)); 889 if (error) 890 continue; 891 break; 892 893 default: 894 laststyle = '/'; 895 addr += temp * objsz; 896 cur_bytes += temp * objsz; 897 if (valid_addr() == 0) 898 continue; 899 } 900 value = get(objsz); 901 continue; 902 903 case '-': /* address subtraction */ 904 colon = 0; 905 c = getachar(); 906 ungetachar(c); 907 if (c == '\n') 908 temp = 1; 909 else { 910 temp = expr(); 911 if (error) 912 continue; 913 } 914 erraddr = addr; 915 errcur_bytes = cur_bytes; 916 switch (objsz) { 917 case DIRECTORY: 918 addr = getdirslot((long)(dirslot - temp)); 919 if (error) 920 continue; 921 break; 922 case INODE: 923 cur_inum -= temp; 924 addr = itob(cur_inum); 925 if (!icheck(addr)) { 926 cur_inum += temp; 927 continue; 928 } 929 break; 930 case CGRP: 931 case SB: 932 cur_cgrp -= temp; 933 if ((addr = cgrp_check(cur_cgrp)) == 0) { 934 cur_cgrp += temp; 935 continue; 936 } 937 break; 938 case SHADOW_DATA: 939 addr = getshadowslot((long)(cur_shad - temp)); 940 if (error) 941 continue; 942 break; 943 default: 944 laststyle = '/'; 945 addr -= temp * objsz; 946 cur_bytes -= temp * objsz; 947 if (valid_addr() == 0) 948 continue; 949 } 950 value = get(objsz); 951 continue; 952 953 case '*': /* address multiplication */ 954 colon = 0; 955 temp = expr(); 956 if (error) 957 continue; 958 if (objsz != INODE && objsz != DIRECTORY) 959 laststyle = '/'; 960 addr *= temp; 961 value = get(objsz); 962 continue; 963 964 case '%': /* address division */ 965 colon = 0; 966 temp = expr(); 967 if (error) 968 continue; 969 if (!temp) { 970 printf("divide by zero\n"); 971 error++; 972 continue; 973 } 974 if (objsz != INODE && objsz != DIRECTORY) 975 laststyle = '/'; 976 addr /= temp; 977 value = get(objsz); 978 continue; 979 980 case '=': { /* assignment operation */ 981 short tbase; 982 calc: 983 tbase = base; 984 985 c = getachar(); 986 if (c == '\n') { 987 ungetachar(c); 988 c = lastpo; 989 if (acting_on_inode == 1) { 990 if (c != 'o' && c != 'd' && c != 'x' && 991 c != 'O' && c != 'D' && c != 'X') { 992 switch (objsz) { 993 case LONG: 994 c = lastpo = 'X'; 995 break; 996 case SHORT: 997 c = lastpo = 'x'; 998 break; 999 case CHAR: 1000 c = lastpo = 'c'; 1001 } 1002 } 1003 } else { 1004 if (acting_on_inode == 2) 1005 c = lastpo = 't'; 1006 } 1007 } else if (acting_on_inode) 1008 lastpo = c; 1009 should_print = star = 0; 1010 count = 1; 1011 erraddr = addr; 1012 errcur_bytes = cur_bytes; 1013 switch (c) { 1014 case '"': /* character string */ 1015 if (type == NUMB) { 1016 blocksize = BLKSIZE; 1017 filesize = BLKSIZE * 2; 1018 cur_bytes = blkoff(fs, addr); 1019 if (objsz == DIRECTORY || 1020 objsz == INODE) 1021 lastpo = 'X'; 1022 } 1023 puta(); 1024 continue; 1025 case '+': /* =+ operator */ 1026 temp = expr(); 1027 value = get(objsz); 1028 if (!error) 1029 put(value+temp, objsz); 1030 continue; 1031 case '-': /* =- operator */ 1032 temp = expr(); 1033 value = get(objsz); 1034 if (!error) 1035 put(value-temp, objsz); 1036 continue; 1037 case 'b': 1038 case 'c': 1039 if (objsz == CGRP) 1040 fprnt('?', c); 1041 else 1042 fprnt('/', c); 1043 continue; 1044 case 'i': 1045 addr = cur_ino; 1046 fprnt('?', 'i'); 1047 continue; 1048 case 's': 1049 fprnt('?', 's'); 1050 continue; 1051 case 't': 1052 case 'T': 1053 laststyle = '='; 1054 printf("\t\t"); 1055 { 1056 /* 1057 * Truncation is intentional so 1058 * ctime is happy. 1059 */ 1060 time_t tvalue = (time_t)value; 1061 printf("%s", ctime(&tvalue)); 1062 } 1063 continue; 1064 case 'o': 1065 base = OCTAL; 1066 goto otx; 1067 case 'd': 1068 if (objsz == DIRECTORY) { 1069 addr = cur_dir; 1070 fprnt('?', 'd'); 1071 continue; 1072 } 1073 base = DECIMAL; 1074 goto otx; 1075 case 'x': 1076 base = HEX; 1077 otx: 1078 laststyle = '='; 1079 printf("\t\t"); 1080 if (acting_on_inode) 1081 print(value & 0177777L, 12, -8, 0); 1082 else 1083 print(addr & 0177777L, 12, -8, 0); 1084 printf("\n"); 1085 base = tbase; 1086 continue; 1087 case 'O': 1088 base = OCTAL; 1089 goto OTX; 1090 case 'D': 1091 base = DECIMAL; 1092 goto OTX; 1093 case 'X': 1094 base = HEX; 1095 OTX: 1096 laststyle = '='; 1097 printf("\t\t"); 1098 if (acting_on_inode) 1099 print(value, 12, -8, 0); 1100 else 1101 print(addr, 12, -8, 0); 1102 printf("\n"); 1103 base = tbase; 1104 continue; 1105 default: /* regular assignment */ 1106 ungetachar(c); 1107 value = expr(); 1108 if (error) 1109 printf("syntax error\n"); 1110 else 1111 put(value, objsz); 1112 continue; 1113 } 1114 } 1115 1116 case '>': /* save current address */ 1117 colon = 0; 1118 should_print = 0; 1119 c = getachar(); 1120 if (!letter(c) && !digit(c)) { 1121 printf("invalid register specification, "); 1122 printf("must be letter or digit\n"); 1123 error++; 1124 continue; 1125 } 1126 if (letter(c)) { 1127 if (c < 'a') 1128 c = uppertolower(c); 1129 c = hextodigit(c); 1130 } else 1131 c = numtodigit(c); 1132 regs[c].sv_addr = addr; 1133 regs[c].sv_value = value; 1134 regs[c].sv_objsz = objsz; 1135 continue; 1136 1137 case '<': /* restore saved address */ 1138 colon = 0; 1139 should_print = 0; 1140 c = getachar(); 1141 if (!letter(c) && !digit(c)) { 1142 printf("invalid register specification, "); 1143 printf("must be letter or digit\n"); 1144 error++; 1145 continue; 1146 } 1147 if (letter(c)) { 1148 if (c < 'a') 1149 c = uppertolower(c); 1150 c = hextodigit(c); 1151 } else 1152 c = numtodigit(c); 1153 addr = regs[c].sv_addr; 1154 value = regs[c].sv_value; 1155 objsz = regs[c].sv_objsz; 1156 continue; 1157 1158 case 'a': 1159 if (colon) 1160 colon = 0; 1161 else 1162 goto no_colon; 1163 if (match("at", 2)) { /* access time */ 1164 acting_on_inode = 2; 1165 should_print = 1; 1166 addr = (long) 1167 &((struct dinode *)cur_ino)->di_atime; 1168 value = get(LONG); 1169 type = NULL; 1170 continue; 1171 } 1172 goto bad_syntax; 1173 1174 case 'b': 1175 if (colon) 1176 colon = 0; 1177 else 1178 goto no_colon; 1179 if (match("block", 2)) { /* block conversion */ 1180 if (type == NUMB) { 1181 value = addr; 1182 cur_bytes = 0; 1183 blocksize = BLKSIZE; 1184 filesize = BLKSIZE * 2; 1185 } 1186 addr = value << FRGSHIFT; 1187 bod_addr = addr; 1188 value = get(LONG); 1189 type = BLOCK; 1190 dirslot = 0; 1191 trapped++; 1192 continue; 1193 } 1194 if (match("bs", 2)) { /* block size */ 1195 acting_on_inode = 1; 1196 should_print = 1; 1197 if (icheck(cur_ino) == 0) 1198 continue; 1199 addr = (long) 1200 &((struct dinode *)cur_ino)->di_blocks; 1201 value = get(LONG); 1202 type = NULL; 1203 continue; 1204 } 1205 if (match("base", 2)) { /* change/show base */ 1206 showbase: 1207 if ((c = getachar()) == '\n') { 1208 ungetachar(c); 1209 printf("base =\t\t"); 1210 switch (base) { 1211 case OCTAL: 1212 printf("OCTAL\n"); 1213 continue; 1214 case DECIMAL: 1215 printf("DECIMAL\n"); 1216 continue; 1217 case HEX: 1218 printf("HEX\n"); 1219 continue; 1220 } 1221 } 1222 if (c != '=') { 1223 printf("missing '='\n"); 1224 error++; 1225 continue; 1226 } 1227 value = expr(); 1228 switch (value) { 1229 default: 1230 printf("invalid base\n"); 1231 error++; 1232 break; 1233 case OCTAL: 1234 case DECIMAL: 1235 case HEX: 1236 base = (short)value; 1237 } 1238 goto showbase; 1239 } 1240 goto bad_syntax; 1241 1242 case 'c': 1243 if (colon) 1244 colon = 0; 1245 else 1246 goto no_colon; 1247 if (match("cd", 2)) { /* change directory */ 1248 top = filenames - 1; 1249 eat_spaces(); 1250 if ((c = getachar()) == '\n') { 1251 ungetachar(c); 1252 current_pathp = -1; 1253 restore_inode(2); 1254 continue; 1255 } 1256 ungetachar(c); 1257 temp = cur_inum; 1258 doing_cd = 1; 1259 parse(); 1260 doing_cd = 0; 1261 if (nfiles != 1) { 1262 restore_inode((ino_t)temp); 1263 if (!error) { 1264 print_path(input_path, 1265 (int)input_pathp); 1266 if (nfiles == 0) 1267 printf(" not found\n"); 1268 else 1269 printf(" ambiguous\n"); 1270 error++; 1271 } 1272 continue; 1273 } 1274 restore_inode(filenames->ino); 1275 if ((mode = icheck(addr)) == 0) 1276 continue; 1277 if ((mode & IFMT) != IFDIR) { 1278 restore_inode((ino_t)temp); 1279 print_path(input_path, 1280 (int)input_pathp); 1281 printf(" not a directory\n"); 1282 error++; 1283 continue; 1284 } 1285 for (i = 0; i <= top->len; i++) 1286 (void) strcpy(current_path[i], 1287 top->fname[i]); 1288 current_pathp = top->len; 1289 continue; 1290 } 1291 if (match("cg", 2)) { /* cylinder group */ 1292 if (type == NUMB) 1293 value = addr; 1294 if (value > fs->fs_ncg - 1) { 1295 printf("maximum cylinder group is "); 1296 print(fs->fs_ncg - 1, 8, -8, 0); 1297 printf("\n"); 1298 error++; 1299 continue; 1300 } 1301 type = objsz = CGRP; 1302 cur_cgrp = (long)value; 1303 addr = cgtod(fs, cur_cgrp) << FRGSHIFT; 1304 continue; 1305 } 1306 if (match("ct", 2)) { /* creation time */ 1307 acting_on_inode = 2; 1308 should_print = 1; 1309 addr = (long) 1310 &((struct dinode *)cur_ino)->di_ctime; 1311 value = get(LONG); 1312 type = NULL; 1313 continue; 1314 } 1315 goto bad_syntax; 1316 1317 case 'd': 1318 if (colon) 1319 colon = 0; 1320 else 1321 goto no_colon; 1322 if (match("directory", 2)) { /* directory offsets */ 1323 if (type == NUMB) 1324 value = addr; 1325 objsz = DIRECTORY; 1326 type = DIRECTORY; 1327 addr = (u_offset_t)getdirslot((long)value); 1328 continue; 1329 } 1330 if (match("db", 2)) { /* direct block */ 1331 acting_on_inode = 1; 1332 should_print = 1; 1333 if (type == NUMB) 1334 value = addr; 1335 if (value >= NDADDR) { 1336 printf("direct blocks are 0 to "); 1337 print(NDADDR - 1, 0, 0, 0); 1338 printf("\n"); 1339 error++; 1340 continue; 1341 } 1342 addr = cur_ino; 1343 if (!icheck(addr)) 1344 continue; 1345 addr = (long) 1346 &((struct dinode *)cur_ino)-> 1347 di_db[value]; 1348 bod_addr = addr; 1349 cur_bytes = (value) * BLKSIZE; 1350 cur_block = (long)value; 1351 type = BLOCK; 1352 dirslot = 0; 1353 value = get(LONG); 1354 if (!value && !override) { 1355 printf("non existent block\n"); 1356 error++; 1357 } 1358 continue; 1359 } 1360 goto bad_syntax; 1361 1362 case 'f': 1363 if (colon) 1364 colon = 0; 1365 else 1366 goto no_colon; 1367 if (match("find", 3)) { /* find command */ 1368 find(); 1369 continue; 1370 } 1371 if (match("fragment", 2)) { /* fragment conv. */ 1372 if (type == NUMB) { 1373 value = addr; 1374 cur_bytes = 0; 1375 blocksize = FRGSIZE; 1376 filesize = FRGSIZE * 2; 1377 } 1378 if (min(blocksize, filesize) - cur_bytes > 1379 FRGSIZE) { 1380 blocksize = cur_bytes + FRGSIZE; 1381 filesize = blocksize * 2; 1382 } 1383 addr = value << FRGSHIFT; 1384 bod_addr = addr; 1385 value = get(LONG); 1386 type = FRAGMENT; 1387 dirslot = 0; 1388 trapped++; 1389 continue; 1390 } 1391 if (match("file", 4)) { /* access as file */ 1392 acting_on_inode = 1; 1393 should_print = 1; 1394 if (type == NUMB) 1395 value = addr; 1396 addr = cur_ino; 1397 if ((mode = icheck(addr)) == 0) 1398 continue; 1399 if (!override) { 1400 switch (mode & IFMT) { 1401 case IFCHR: 1402 case IFBLK: 1403 printf("special device\n"); 1404 error++; 1405 continue; 1406 } 1407 } 1408 if ((addr = (u_offset_t) 1409 (bmap((long)value) << FRGSHIFT)) == 0) 1410 continue; 1411 cur_block = (long)value; 1412 bod_addr = addr; 1413 type = BLOCK; 1414 dirslot = 0; 1415 continue; 1416 } 1417 if (match("fill", 4)) { /* fill */ 1418 if (getachar() != '=') { 1419 printf("missing '='\n"); 1420 error++; 1421 continue; 1422 } 1423 if (objsz == INODE || objsz == DIRECTORY || 1424 objsz == SHADOW_DATA) { 1425 printf( 1426 "can't fill inode or directory\n"); 1427 error++; 1428 continue; 1429 } 1430 fill(); 1431 continue; 1432 } 1433 goto bad_syntax; 1434 1435 case 'g': 1436 if (colon) 1437 colon = 0; 1438 else 1439 goto no_colon; 1440 if (match("gid", 1)) { /* group id */ 1441 acting_on_inode = 1; 1442 should_print = 1; 1443 addr = (long) 1444 &((struct dinode *)cur_ino)->di_gid; 1445 value = get(SHORT); 1446 type = NULL; 1447 continue; 1448 } 1449 goto bad_syntax; 1450 1451 case 'i': 1452 if (colon) 1453 colon = 0; 1454 else 1455 goto no_colon; 1456 if (match("inode", 2)) { /* i# to inode conversion */ 1457 if (c_count == 2) { 1458 addr = cur_ino; 1459 value = get(INODE); 1460 type = NULL; 1461 laststyle = '='; 1462 lastpo = 'i'; 1463 should_print = 1; 1464 continue; 1465 } 1466 if (type == NUMB) 1467 value = addr; 1468 addr = itob(value); 1469 if (!icheck(addr)) 1470 continue; 1471 cur_ino = addr; 1472 cur_inum = (long)value; 1473 value = get(INODE); 1474 type = NULL; 1475 continue; 1476 } 1477 if (match("ib", 2)) { /* indirect block */ 1478 acting_on_inode = 1; 1479 should_print = 1; 1480 if (type == NUMB) 1481 value = addr; 1482 if (value >= NIADDR) { 1483 printf("indirect blocks are 0 to "); 1484 print(NIADDR - 1, 0, 0, 0); 1485 printf("\n"); 1486 error++; 1487 continue; 1488 } 1489 addr = (long)&((struct dinode *)cur_ino)-> 1490 di_ib[value]; 1491 cur_bytes = (NDADDR - 1) * BLKSIZE; 1492 temp = 1; 1493 for (i = 0; i < value; i++) { 1494 temp *= NINDIR(fs) * BLKSIZE; 1495 cur_bytes += temp; 1496 } 1497 type = BLOCK; 1498 dirslot = 0; 1499 value = get(LONG); 1500 if (!value && !override) { 1501 printf("non existent block\n"); 1502 error++; 1503 } 1504 continue; 1505 } 1506 goto bad_syntax; 1507 1508 case 'l': 1509 if (colon) 1510 colon = 0; 1511 else 1512 goto no_colon; 1513 if (match("log_head", 8)) { 1514 log_display_header(); 1515 should_print = 0; 1516 continue; 1517 } 1518 if (match("log_delta", 9)) { 1519 log_show(LOG_NDELTAS); 1520 should_print = 0; 1521 continue; 1522 } 1523 if (match("log_show", 8)) { 1524 log_show(LOG_ALLDELTAS); 1525 should_print = 0; 1526 continue; 1527 } 1528 if (match("log_chk", 7)) { 1529 log_show(LOG_CHECKSCAN); 1530 should_print = 0; 1531 continue; 1532 } 1533 if (match("log_otodb", 9)) { 1534 if (log_lodb((u_offset_t)addr, &temp)) { 1535 addr = temp; 1536 should_print = 1; 1537 laststyle = '='; 1538 } else 1539 error++; 1540 continue; 1541 } 1542 if (match("ls", 2)) { /* ls command */ 1543 temp = cur_inum; 1544 recursive = long_list = 0; 1545 top = filenames - 1; 1546 for (;;) { 1547 eat_spaces(); 1548 if ((c = getachar()) == '-') { 1549 if ((c = getachar()) == 'R') { 1550 recursive = 1; 1551 continue; 1552 } else if (c == 'l') { 1553 long_list = 1; 1554 } else { 1555 printf( 1556 "unknown option "); 1557 printf("'%c'\n", c); 1558 error++; 1559 break; 1560 } 1561 } else 1562 ungetachar(c); 1563 if ((c = getachar()) == '\n') { 1564 if (c_count != 2) { 1565 ungetachar(c); 1566 break; 1567 } 1568 } 1569 c_count++; 1570 ungetachar(c); 1571 parse(); 1572 restore_inode((ino_t)temp); 1573 if (error) 1574 break; 1575 } 1576 recursive = 0; 1577 if (error || nfiles == 0) { 1578 if (!error) { 1579 print_path(input_path, 1580 (int)input_pathp); 1581 printf(" not found\n"); 1582 } 1583 continue; 1584 } 1585 if (nfiles) { 1586 cmp_level = 0; 1587 qsort((char *)filenames, nfiles, 1588 sizeof (struct filenames), ffcmp); 1589 ls(filenames, filenames + (nfiles - 1), 0); 1590 } else { 1591 printf("no match\n"); 1592 error++; 1593 } 1594 restore_inode((ino_t)temp); 1595 continue; 1596 } 1597 if (match("ln", 2)) { /* link count */ 1598 acting_on_inode = 1; 1599 should_print = 1; 1600 addr = (long) 1601 &((struct dinode *)cur_ino)->di_nlink; 1602 value = get(SHORT); 1603 type = NULL; 1604 continue; 1605 } 1606 goto bad_syntax; 1607 1608 case 'm': 1609 if (colon) 1610 colon = 0; 1611 else 1612 goto no_colon; 1613 addr = cur_ino; 1614 if ((mode = icheck(addr)) == 0) 1615 continue; 1616 if (match("mt", 2)) { /* modification time */ 1617 acting_on_inode = 2; 1618 should_print = 1; 1619 addr = (long) 1620 &((struct dinode *)cur_ino)->di_mtime; 1621 value = get(LONG); 1622 type = NULL; 1623 continue; 1624 } 1625 if (match("md", 2)) { /* mode */ 1626 acting_on_inode = 1; 1627 should_print = 1; 1628 addr = (long) 1629 &((struct dinode *)cur_ino)->di_mode; 1630 value = get(SHORT); 1631 type = NULL; 1632 continue; 1633 } 1634 if (match("maj", 2)) { /* major device number */ 1635 acting_on_inode = 1; 1636 should_print = 1; 1637 if (devcheck(mode)) 1638 continue; 1639 addr = (uintptr_t) 1640 &((struct dinode *)cur_ino)->di_ordev; 1641 { 1642 long dvalue; 1643 dvalue = get(LONG); 1644 value = major(dvalue); 1645 } 1646 type = NULL; 1647 continue; 1648 } 1649 if (match("min", 2)) { /* minor device number */ 1650 acting_on_inode = 1; 1651 should_print = 1; 1652 if (devcheck(mode)) 1653 continue; 1654 addr = (uintptr_t) 1655 &((struct dinode *)cur_ino)->di_ordev; 1656 { 1657 long dvalue; 1658 dvalue = (long)get(LONG); 1659 value = minor(dvalue); 1660 } 1661 type = NULL; 1662 continue; 1663 } 1664 goto bad_syntax; 1665 1666 case 'n': 1667 if (colon) 1668 colon = 0; 1669 else 1670 goto no_colon; 1671 if (match("nm", 1)) { /* directory name */ 1672 objsz = DIRECTORY; 1673 acting_on_directory = 1; 1674 cur_dir = addr; 1675 if ((cptr = getblk(addr)) == 0) 1676 continue; 1677 /*LINTED*/ 1678 dirp = (struct direct *)(cptr+blkoff(fs, addr)); 1679 stringsize = (long)dirp->d_reclen - 1680 ((long)&dirp->d_name[0] - 1681 (long)&dirp->d_ino); 1682 addr = (long) 1683 &((struct direct *)addr)->d_name[0]; 1684 type = NULL; 1685 continue; 1686 } 1687 goto bad_syntax; 1688 1689 case 'o': 1690 if (colon) 1691 colon = 0; 1692 else 1693 goto no_colon; 1694 if (match("override", 1)) { /* override flip flop */ 1695 override = !override; 1696 if (override) 1697 printf("error checking off\n"); 1698 else 1699 printf("error checking on\n"); 1700 continue; 1701 } 1702 goto bad_syntax; 1703 1704 case 'p': 1705 if (colon) 1706 colon = 0; 1707 else 1708 goto no_colon; 1709 if (match("pwd", 2)) { /* print working dir */ 1710 print_path(current_path, (int)current_pathp); 1711 printf("\n"); 1712 continue; 1713 } 1714 if (match("prompt", 2)) { /* change prompt */ 1715 if ((c = getachar()) != '=') { 1716 printf("missing '='\n"); 1717 error++; 1718 continue; 1719 } 1720 if ((c = getachar()) != '"') { 1721 printf("missing '\"'\n"); 1722 error++; 1723 continue; 1724 } 1725 i = 0; 1726 prompt = &prompt[0]; 1727 while ((c = getachar()) != '"' && c != '\n') { 1728 prompt[i++] = c; 1729 if (i >= PROMPTSIZE) { 1730 printf("string too long\n"); 1731 error++; 1732 break; 1733 } 1734 } 1735 prompt[i] = '\0'; 1736 continue; 1737 } 1738 goto bad_syntax; 1739 1740 case 'q': 1741 if (!colon) 1742 goto no_colon; 1743 if (match("quit", 1)) { /* quit */ 1744 if ((c = getachar()) != '\n') { 1745 error++; 1746 continue; 1747 } 1748 exit(0); 1749 } 1750 goto bad_syntax; 1751 1752 case 's': 1753 if (colon) 1754 colon = 0; 1755 else 1756 goto no_colon; 1757 if (match("sb", 2)) { /* super block */ 1758 if (c_count == 2) { 1759 cur_cgrp = -1; 1760 type = objsz = SB; 1761 laststyle = '='; 1762 lastpo = 's'; 1763 should_print = 1; 1764 continue; 1765 } 1766 if (type == NUMB) 1767 value = addr; 1768 if (value > fs->fs_ncg - 1) { 1769 printf("maximum super block is "); 1770 print(fs->fs_ncg - 1, 8, -8, 0); 1771 printf("\n"); 1772 error++; 1773 continue; 1774 } 1775 type = objsz = SB; 1776 cur_cgrp = (long)value; 1777 addr = cgsblock(fs, cur_cgrp) << FRGSHIFT; 1778 continue; 1779 } 1780 if (match("shadow", 2)) { /* shadow inode data */ 1781 if (type == NUMB) 1782 value = addr; 1783 objsz = SHADOW_DATA; 1784 type = SHADOW_DATA; 1785 addr = getshadowslot(value); 1786 continue; 1787 } 1788 if (match("si", 2)) { /* shadow inode field */ 1789 acting_on_inode = 1; 1790 should_print = 1; 1791 addr = (long) 1792 &((struct dinode *)cur_ino)->di_shadow; 1793 value = get(LONG); 1794 type = NULL; 1795 continue; 1796 } 1797 1798 if (match("sz", 2)) { /* file size */ 1799 acting_on_inode = 1; 1800 should_print = 1; 1801 addr = (long) 1802 &((struct dinode *)cur_ino)->di_size; 1803 value = get(U_OFFSET_T); 1804 type = NULL; 1805 objsz = U_OFFSET_T; 1806 laststyle = '='; 1807 lastpo = 'X'; 1808 continue; 1809 } 1810 goto bad_syntax; 1811 1812 case 'u': 1813 if (colon) 1814 colon = 0; 1815 else 1816 goto no_colon; 1817 if (match("uid", 1)) { /* user id */ 1818 acting_on_inode = 1; 1819 should_print = 1; 1820 addr = (long) 1821 &((struct dinode *)cur_ino)->di_uid; 1822 value = get(SHORT); 1823 type = NULL; 1824 continue; 1825 } 1826 goto bad_syntax; 1827 1828 case 'F': /* buffer status (internal use only) */ 1829 if (colon) 1830 colon = 0; 1831 else 1832 goto no_colon; 1833 for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd) 1834 printf("%8" PRIx64 " %d\n", 1835 bp->blkno, bp->valid); 1836 printf("\n"); 1837 printf("# commands\t\t%ld\n", commands); 1838 printf("# read requests\t\t%ld\n", read_requests); 1839 printf("# actual disk reads\t%ld\n", actual_disk_reads); 1840 continue; 1841 no_colon: 1842 printf("a colon should precede a command\n"); 1843 error++; 1844 continue; 1845 bad_syntax: 1846 printf("more letters needed to distinguish command\n"); 1847 error++; 1848 continue; 1849 } 1850 } 1851 } 1852 1853 /* 1854 * usage - print usage and exit 1855 */ 1856 static void 1857 usage(progname) 1858 char *progname; 1859 { 1860 printf("usage: %s [options] special\n", progname); 1861 printf("options:\n"); 1862 printf("\t-o Specify ufs filesystem sepcific options\n"); 1863 printf(" Available suboptions are:\n"); 1864 printf("\t\t? display usage\n"); 1865 printf("\t\to override some error conditions\n"); 1866 printf("\t\tp=\"string\" set prompt to string\n"); 1867 printf("\t\tw open for write\n"); 1868 exit(1); 1869 } 1870 1871 /* 1872 * getachar - get next character from input buffer. 1873 */ 1874 static char 1875 getachar() 1876 { 1877 return (input_buffer[input_pointer++]); 1878 } 1879 1880 /* 1881 * ungetachar - return character to input buffer. 1882 */ 1883 static void 1884 ungetachar(c) 1885 register char c; 1886 { 1887 if (input_pointer == 0) { 1888 printf("internal problem maintaining input buffer\n"); 1889 error++; 1890 return; 1891 } 1892 input_buffer[--input_pointer] = c; 1893 } 1894 1895 /* 1896 * getnextinput - display the prompt and read an input line. 1897 * An input line is up to 128 characters terminated by the newline 1898 * character. Handle overflow, shell escape, and eof. 1899 */ 1900 static void 1901 getnextinput() 1902 { 1903 register int i; 1904 register char c; 1905 register short pid, rpid; 1906 int retcode; 1907 1908 newline: 1909 i = 0; 1910 printf("%s", prompt); 1911 ignore_eol: 1912 while ((c = getc(stdin)) != '\n' && !(c == '!' && i == 0) && 1913 !feof(stdin) && i <= INPUTBUFFER - 2) 1914 input_buffer[i++] = c; 1915 if (i > 0 && input_buffer[i - 1] == '\\') { 1916 input_buffer[i++] = c; 1917 goto ignore_eol; 1918 } 1919 if (feof(stdin)) { 1920 printf("\n"); 1921 exit(0); 1922 } 1923 if (c == '!') { 1924 if ((pid = fork()) == 0) { 1925 (void) execl(_PATH_BSHELL, "sh", "-t", 0); 1926 error++; 1927 return; 1928 } 1929 while ((rpid = wait(&retcode)) != pid && rpid != -1) 1930 ; 1931 printf("!\n"); 1932 goto newline; 1933 } 1934 if (c != '\n') 1935 printf("input truncated to 128 characters\n"); 1936 input_buffer[i] = '\n'; 1937 input_pointer = 0; 1938 } 1939 1940 /* 1941 * eat_spaces - read extraneous spaces. 1942 */ 1943 static void 1944 eat_spaces() 1945 { 1946 register char c; 1947 1948 while ((c = getachar()) == ' ') 1949 ; 1950 ungetachar(c); 1951 } 1952 1953 /* 1954 * restore_inode - set up all inode indicators so inum is now 1955 * the current inode. 1956 */ 1957 static void 1958 restore_inode(inum) 1959 ino_t inum; 1960 { 1961 errinum = cur_inum = inum; 1962 addr = errino = cur_ino = itob(inum); 1963 } 1964 1965 /* 1966 * match - return false if the input does not match string up to 1967 * upto letters. Then proceed to chew up extraneous letters. 1968 */ 1969 static int 1970 match(string, upto) 1971 register char *string; 1972 register int upto; 1973 { 1974 register int i, length = strlen(string) - 1; 1975 register char c; 1976 int save_upto = upto; 1977 1978 while (--upto) { 1979 string++; 1980 if ((c = getachar()) != *string) { 1981 for (i = save_upto - upto; i; i--) { 1982 ungetachar(c); 1983 c = *--string; 1984 } 1985 return (0); 1986 } 1987 length--; 1988 } 1989 while (length--) { 1990 string++; 1991 if ((c = getachar()) != *string) { 1992 ungetachar(c); 1993 return (1); 1994 } 1995 } 1996 return (1); 1997 } 1998 1999 /* 2000 * expr - expression evaluator. Will evaluate expressions from 2001 * left to right with no operator precedence. Parentheses may 2002 * be used. 2003 */ 2004 static long 2005 expr() 2006 { 2007 register long numb = 0, temp; 2008 register char c; 2009 2010 numb = term(); 2011 for (;;) { 2012 if (error) 2013 return (~0); /* error is set so value is ignored */ 2014 c = getachar(); 2015 switch (c) { 2016 2017 case '+': 2018 numb += term(); 2019 continue; 2020 2021 case '-': 2022 numb -= term(); 2023 continue; 2024 2025 case '*': 2026 numb *= term(); 2027 continue; 2028 2029 case '%': 2030 temp = term(); 2031 if (!temp) { 2032 printf("divide by zero\n"); 2033 error++; 2034 return (~0); 2035 } 2036 numb /= temp; 2037 continue; 2038 2039 case ')': 2040 paren--; 2041 return (numb); 2042 2043 default: 2044 ungetachar(c); 2045 if (paren && !error) { 2046 printf("missing ')'\n"); 2047 error++; 2048 } 2049 return (numb); 2050 } 2051 } 2052 } 2053 2054 /* 2055 * term - used by expression evaluator to get an operand. 2056 */ 2057 static long 2058 term() 2059 { 2060 register char c; 2061 2062 switch (c = getachar()) { 2063 2064 default: 2065 ungetachar(c); 2066 /*FALLTHRU*/ 2067 case '+': 2068 return (getnumb()); 2069 2070 case '-': 2071 return (-getnumb()); 2072 2073 case '(': 2074 paren++; 2075 return (expr()); 2076 } 2077 } 2078 2079 /* 2080 * getnumb - read a number from the input stream. A leading 2081 * zero signifies octal interpretation, a leading '0x' 2082 * signifies hexadecimal, and a leading '0t' signifies 2083 * decimal. If the first character is a character, 2084 * return an error. 2085 */ 2086 static long 2087 getnumb() 2088 { 2089 2090 register char c, savec; 2091 long number = 0, tbase, num; 2092 extern short error; 2093 2094 c = getachar(); 2095 if (!digit(c)) { 2096 error++; 2097 ungetachar(c); 2098 return (-1); 2099 } 2100 if (c == '0') { 2101 tbase = OCTAL; 2102 if ((c = getachar()) == 'x') 2103 tbase = HEX; 2104 else if (c == 't') 2105 tbase = DECIMAL; 2106 else ungetachar(c); 2107 } else { 2108 tbase = base; 2109 ungetachar(c); 2110 } 2111 for (;;) { 2112 num = tbase; 2113 c = savec = getachar(); 2114 if (HEXLETTER(c)) 2115 c = uppertolower(c); 2116 switch (tbase) { 2117 case HEX: 2118 if (hexletter(c)) { 2119 num = hextodigit(c); 2120 break; 2121 } 2122 /*FALLTHRU*/ 2123 case DECIMAL: 2124 if (digit(c)) 2125 num = numtodigit(c); 2126 break; 2127 case OCTAL: 2128 if (octaldigit(c)) 2129 num = numtodigit(c); 2130 } 2131 if (num == tbase) 2132 break; 2133 number = number * tbase + num; 2134 } 2135 ungetachar(savec); 2136 return (number); 2137 } 2138 2139 /* 2140 * find - the syntax is almost identical to the unix command. 2141 * find dir [-name pattern] [-inum number] 2142 * Note: only one of -name or -inum may be used at a time. 2143 * Also, the -print is not needed (implied). 2144 */ 2145 static void 2146 find() 2147 { 2148 register struct filenames *fn; 2149 register char c; 2150 long temp; 2151 short mode; 2152 2153 eat_spaces(); 2154 temp = cur_inum; 2155 top = filenames - 1; 2156 doing_cd = 1; 2157 parse(); 2158 doing_cd = 0; 2159 if (nfiles != 1) { 2160 restore_inode((ino_t)temp); 2161 if (!error) { 2162 print_path(input_path, (int)input_pathp); 2163 if (nfiles == 0) 2164 printf(" not found\n"); 2165 else 2166 printf(" ambiguous\n"); 2167 error++; 2168 return; 2169 } 2170 } 2171 restore_inode(filenames->ino); 2172 freemem(filenames, nfiles); 2173 nfiles = 0; 2174 top = filenames - 1; 2175 if ((mode = icheck(addr)) == 0) 2176 return; 2177 if ((mode & IFMT) != IFDIR) { 2178 print_path(input_path, (int)input_pathp); 2179 printf(" not a directory\n"); 2180 error++; 2181 return; 2182 } 2183 eat_spaces(); 2184 if ((c = getachar()) != '-') { 2185 restore_inode((ino_t)temp); 2186 printf("missing '-'\n"); 2187 error++; 2188 return; 2189 } 2190 find_by_name = find_by_inode = 0; 2191 c = getachar(); 2192 if (match("name", 4)) { 2193 eat_spaces(); 2194 find_by_name = 1; 2195 } else if (match("inum", 4)) { 2196 eat_spaces(); 2197 find_ino = expr(); 2198 if (error) { 2199 restore_inode((ino_t)temp); 2200 return; 2201 } 2202 while ((c = getachar()) != '\n') 2203 ; 2204 ungetachar(c); 2205 find_by_inode = 1; 2206 } else { 2207 restore_inode((ino_t)temp); 2208 printf("use -name or -inum with find\n"); 2209 error++; 2210 return; 2211 } 2212 doing_find = 1; 2213 parse(); 2214 doing_find = 0; 2215 if (error) { 2216 restore_inode((ino_t)temp); 2217 return; 2218 } 2219 for (fn = filenames; fn <= top; fn++) { 2220 if (fn->find == 0) 2221 continue; 2222 printf("i#: "); 2223 print(fn->ino, 12, -8, 0); 2224 print_path(fn->fname, (int)fn->len); 2225 printf("\n"); 2226 } 2227 restore_inode((ino_t)temp); 2228 } 2229 2230 /* 2231 * ls - do an ls. Should behave exactly as ls(1). 2232 * Only -R and -l is supported and -l gives different results. 2233 */ 2234 static void 2235 ls(fn0, fnlast, level) 2236 struct filenames *fn0, *fnlast; 2237 short level; 2238 { 2239 register struct filenames *fn, *fnn; 2240 2241 fn = fn0; 2242 for (;;) { 2243 fn0 = fn; 2244 if (fn0->len) { 2245 cmp_level = level; 2246 qsort((char *)fn0, fnlast - fn0 + 1, 2247 sizeof (struct filenames), fcmp); 2248 } 2249 for (fnn = fn, fn++; fn <= fnlast; fnn = fn, fn++) { 2250 if (fnn->len != fn->len && level == fnn->len - 1) 2251 break; 2252 if (fnn->len == 0) 2253 continue; 2254 if (strcmp(fn->fname[level], fnn->fname[level])) 2255 break; 2256 } 2257 if (fn0->len && level != fn0->len - 1) 2258 ls(fn0, fnn, level + 1); 2259 else { 2260 if (fn0 != filenames) 2261 printf("\n"); 2262 print_path(fn0->fname, (int)(fn0->len - 1)); 2263 printf(":\n"); 2264 if (fn0->len == 0) 2265 cmp_level = level; 2266 else 2267 cmp_level = level + 1; 2268 qsort((char *)fn0, fnn - fn0 + 1, 2269 sizeof (struct filenames), fcmp); 2270 formatf(fn0, fnn); 2271 nfiles -= fnn - fn0 + 1; 2272 } 2273 if (fn > fnlast) 2274 return; 2275 } 2276 } 2277 2278 /* 2279 * formatf - code lifted from ls. 2280 */ 2281 static void 2282 formatf(fn0, fnlast) 2283 register struct filenames *fn0, *fnlast; 2284 { 2285 register struct filenames *fn; 2286 int width = 0, w, nentry = fnlast - fn0 + 1; 2287 int i, j, columns, lines; 2288 char *cp; 2289 2290 if (long_list) { 2291 columns = 1; 2292 } else { 2293 for (fn = fn0; fn <= fnlast; fn++) { 2294 int len = strlen(fn->fname[cmp_level]) + 2; 2295 2296 if (len > width) 2297 width = len; 2298 } 2299 width = (width + 8) &~ 7; 2300 columns = 80 / width; 2301 if (columns == 0) 2302 columns = 1; 2303 } 2304 lines = (nentry + columns - 1) / columns; 2305 for (i = 0; i < lines; i++) { 2306 for (j = 0; j < columns; j++) { 2307 fn = fn0 + j * lines + i; 2308 if (long_list) { 2309 printf("i#: "); 2310 print(fn->ino, 12, -8, 0); 2311 } 2312 if ((cp = fmtentry(fn)) == NULL) { 2313 printf("cannot read inode %ld\n", fn->ino); 2314 return; 2315 } 2316 printf("%s", cp); 2317 if (fn + lines > fnlast) { 2318 printf("\n"); 2319 break; 2320 } 2321 w = strlen(cp); 2322 while (w < width) { 2323 w = (w + 8) &~ 7; 2324 (void) putchar('\t'); 2325 } 2326 } 2327 } 2328 } 2329 2330 /* 2331 * fmtentry - code lifted from ls. 2332 */ 2333 static char * 2334 fmtentry(fn) 2335 register struct filenames *fn; 2336 { 2337 static char fmtres[BUFSIZ]; 2338 register struct dinode *ip; 2339 register char *cptr, *cp, *dp; 2340 2341 dp = &fmtres[0]; 2342 for (cp = fn->fname[cmp_level]; *cp; cp++) { 2343 if (*cp < ' ' || *cp >= 0177) 2344 *dp++ = '?'; 2345 else 2346 *dp++ = *cp; 2347 } 2348 addr = itob(fn->ino); 2349 if ((cptr = getblk(addr)) == 0) 2350 return (NULL); 2351 cptr += blkoff(fs, addr); 2352 /*LINTED*/ 2353 ip = (struct dinode *)cptr; 2354 switch (ip->di_mode & IFMT) { 2355 case IFDIR: 2356 *dp++ = '/'; 2357 break; 2358 case IFLNK: 2359 *dp++ = '@'; 2360 break; 2361 case IFSOCK: 2362 *dp++ = '='; 2363 break; 2364 #ifdef IFIFO 2365 case IFIFO: 2366 *dp++ = 'p'; 2367 break; 2368 #endif 2369 case IFCHR: 2370 case IFBLK: 2371 case IFREG: 2372 if (ip->di_mode & 0111) 2373 *dp++ = '*'; 2374 else 2375 *dp++ = ' '; 2376 break; 2377 default: 2378 *dp++ = '?'; 2379 2380 } 2381 *dp++ = 0; 2382 return (fmtres); 2383 } 2384 2385 /* 2386 * fcmp - routine used by qsort. Will sort first by name, then 2387 * then by pathname length if names are equal. Uses global 2388 * cmp_level to tell what component of the path name we are comparing. 2389 */ 2390 static int 2391 fcmp(f1, f2) 2392 register struct filenames *f1, *f2; 2393 { 2394 int value; 2395 2396 if ((value = strcmp(f1->fname[cmp_level], f2->fname[cmp_level]))) 2397 return (value); 2398 return (f1->len - f2->len); 2399 } 2400 2401 /* 2402 * ffcmp - routine used by qsort. Sort only by pathname length. 2403 */ 2404 static int 2405 ffcmp(f1, f2) 2406 register struct filenames *f1, *f2; 2407 { 2408 return (f1->len - f2->len); 2409 } 2410 2411 /* 2412 * parse - set up the call to follow_path. 2413 */ 2414 static void 2415 parse() 2416 { 2417 register int i; 2418 char c; 2419 2420 stack_pathp = input_pathp = -1; 2421 if ((c = getachar()) == '/') { 2422 while ((c = getachar()) == '/') 2423 ; 2424 ungetachar(c); 2425 cur_inum = 2; 2426 c = getachar(); 2427 if ((c == '\n') || ((doing_cd) && (c == ' '))) { 2428 ungetachar(c); 2429 if (doing_cd) { 2430 top++; 2431 top->ino = 2; 2432 top->len = -1; 2433 nfiles = 1; 2434 return; 2435 } 2436 } else 2437 ungetachar(c); 2438 } else { 2439 ungetachar(c); 2440 stack_pathp = current_pathp; 2441 if (!doing_find) 2442 input_pathp = current_pathp; 2443 for (i = 0; i <= current_pathp; i++) { 2444 if (!doing_find) 2445 (void) strcpy(input_path[i], current_path[i]); 2446 (void) strcpy(stack_path[i], current_path[i]); 2447 } 2448 } 2449 getname(); 2450 follow_path((long)(stack_pathp + 1), cur_inum); 2451 } 2452 2453 /* 2454 * follow_path - called by cd, find, and ls. 2455 * input_path holds the name typed by the user. 2456 * stack_path holds the name at the current depth. 2457 */ 2458 static void 2459 follow_path(level, inum) 2460 long level, inum; 2461 { 2462 register struct direct *dirp; 2463 register char **ccptr, *cptr; 2464 register int i; 2465 struct filenames *tos, *bos, *fn, *fnn, *fnnn; 2466 long block; 2467 short mode; 2468 2469 tos = top + 1; 2470 restore_inode((ino_t)inum); 2471 if ((mode = icheck(addr)) == 0) 2472 return; 2473 if ((mode & IFMT) != IFDIR) 2474 return; 2475 block = cur_bytes = 0; 2476 while (cur_bytes < filesize) { 2477 if (block == 0 || bcomp(addr)) { 2478 error = 0; 2479 if ((addr = ((u_offset_t)bmap(block++) << 2480 (u_offset_t)FRGSHIFT)) == 0) 2481 break; 2482 if ((cptr = getblk(addr)) == 0) 2483 break; 2484 cptr += blkoff(fs, addr); 2485 } 2486 /*LINTED*/ 2487 dirp = (struct direct *)cptr; 2488 if (dirp->d_ino) { 2489 if (level > input_pathp || doing_find || 2490 compare(input_path[level], &dirp->d_name[0], 1)) { 2491 if ((doing_find) && 2492 ((strcmp(dirp->d_name, ".") == 0 || 2493 strcmp(dirp->d_name, "..") == 0))) 2494 goto duplicate; 2495 if (++top - filenames >= maxfiles) { 2496 printf("too many files\n"); 2497 error++; 2498 return; 2499 } 2500 top->fname = (char **)calloc(FIRST_DEPTH, sizeof (char **)); 2501 top->flag = 0; 2502 if (top->fname == 0) { 2503 printf("out of memory\n"); 2504 error++; 2505 return; 2506 } 2507 nfiles++; 2508 top->ino = dirp->d_ino; 2509 top->len = stack_pathp; 2510 top->find = 0; 2511 if (doing_find) { 2512 if (find_by_name) { 2513 if (compare(input_path[0], &dirp->d_name[0], 1)) 2514 top->find = 1; 2515 } else if (find_by_inode) 2516 if (find_ino == dirp->d_ino) 2517 top->find = 1; 2518 } 2519 if (top->len + 1 >= FIRST_DEPTH && top->flag == 0) { 2520 ccptr = (char **)calloc(SECOND_DEPTH, sizeof (char **)); 2521 if (ccptr == 0) { 2522 printf("out of memory\n"); 2523 error++; 2524 return; 2525 } 2526 for (i = 0; i < FIRST_DEPTH; i++) 2527 ccptr[i] = top->fname[i]; 2528 free((char *)top->fname); 2529 top->fname = ccptr; 2530 top->flag = 1; 2531 } 2532 if (top->len >= SECOND_DEPTH) { 2533 printf("maximum depth exceeded, try to cd lower\n"); 2534 error++; 2535 return; 2536 } 2537 /* 2538 * Copy current depth. 2539 */ 2540 for (i = 0; i <= stack_pathp; i++) { 2541 top->fname[i] = calloc(1, strlen(stack_path[i])+1); 2542 if (top->fname[i] == 0) { 2543 printf("out of memory\n"); 2544 error++; 2545 return; 2546 } 2547 (void) strcpy(top->fname[i], stack_path[i]); 2548 } 2549 /* 2550 * Check for '.' or '..' typed. 2551 */ 2552 if ((level <= input_pathp) && 2553 (strcmp(input_path[level], ".") == 0 || 2554 strcmp(input_path[level], "..") == 0)) { 2555 if (strcmp(input_path[level], "..") == 0 && 2556 top->len >= 0) { 2557 free(top->fname[top->len]); 2558 top->len -= 1; 2559 } 2560 } else { 2561 /* 2562 * Check for duplicates. 2563 */ 2564 if (!doing_cd && !doing_find) { 2565 for (fn = filenames; fn < top; fn++) { 2566 if (fn->ino == dirp->d_ino && 2567 fn->len == stack_pathp + 1) { 2568 for (i = 0; i < fn->len; i++) 2569 if (strcmp(fn->fname[i], stack_path[i])) 2570 break; 2571 if (i != fn->len || 2572 strcmp(fn->fname[i], dirp->d_name)) 2573 continue; 2574 freemem(top, 1); 2575 if (top == filenames) 2576 top = NULL; 2577 else 2578 top--; 2579 nfiles--; 2580 goto duplicate; 2581 } 2582 } 2583 } 2584 top->len += 1; 2585 top->fname[top->len] = calloc(1, 2586 strlen(&dirp->d_name[0])+1); 2587 if (top->fname[top->len] == 0) { 2588 printf("out of memory\n"); 2589 error++; 2590 return; 2591 } 2592 (void) strcpy(top->fname[top->len], &dirp->d_name[0]); 2593 } 2594 } 2595 } 2596 duplicate: 2597 addr += dirp->d_reclen; 2598 cptr += dirp->d_reclen; 2599 cur_bytes += dirp->d_reclen; 2600 } 2601 if (top < filenames) 2602 return; 2603 if ((doing_cd && level == input_pathp) || 2604 (!recursive && !doing_find && level > input_pathp)) 2605 return; 2606 bos = top; 2607 /* 2608 * Check newly added entries to determine if further expansion 2609 * is required. 2610 */ 2611 for (fn = tos; fn <= bos; fn++) { 2612 /* 2613 * Avoid '.' and '..' if beyond input. 2614 */ 2615 if ((recursive || doing_find) && (level > input_pathp) && 2616 (strcmp(fn->fname[fn->len], ".") == 0 || 2617 strcmp(fn->fname[fn->len], "..") == 0)) 2618 continue; 2619 restore_inode(fn->ino); 2620 if ((mode = icheck(cur_ino)) == 0) 2621 return; 2622 if ((mode & IFMT) == IFDIR || level < input_pathp) { 2623 /* 2624 * Set up current depth, remove current entry and 2625 * continue recursion. 2626 */ 2627 for (i = 0; i <= fn->len; i++) 2628 (void) strcpy(stack_path[i], fn->fname[i]); 2629 stack_pathp = fn->len; 2630 if (!doing_find && 2631 (!recursive || (recursive && level <= input_pathp))) { 2632 /* 2633 * Remove current entry by moving others up. 2634 */ 2635 freemem(fn, 1); 2636 fnn = fn; 2637 for (fnnn = fnn, fnn++; fnn <= top; fnnn = fnn, fnn++) { 2638 fnnn->ino = fnn->ino; 2639 fnnn->len = fnn->len; 2640 if (fnnn->len + 1 < FIRST_DEPTH) { 2641 fnnn->fname = (char **)calloc(FIRST_DEPTH, 2642 sizeof (char **)); 2643 fnnn->flag = 0; 2644 } else if (fnnn->len < SECOND_DEPTH) { 2645 fnnn->fname = (char **)calloc(SECOND_DEPTH, 2646 sizeof (char **)); 2647 fnnn->flag = 1; 2648 } else { 2649 printf("maximum depth exceeded, "); 2650 printf("try to cd lower\n"); 2651 error++; 2652 return; 2653 } 2654 for (i = 0; i <= fnn->len; i++) 2655 fnnn->fname[i] = fnn->fname[i]; 2656 } 2657 if (fn == tos) 2658 fn--; 2659 top--; 2660 bos--; 2661 nfiles--; 2662 } 2663 follow_path(level + 1, cur_inum); 2664 if (error) 2665 return; 2666 } 2667 } 2668 } 2669 2670 /* 2671 * getname - break up the pathname entered by the user into components. 2672 */ 2673 static void 2674 getname() 2675 { 2676 register int i; 2677 char c; 2678 2679 if ((c = getachar()) == '\n') { 2680 ungetachar(c); 2681 return; 2682 } 2683 ungetachar(c); 2684 input_pathp++; 2685 clear: 2686 for (i = 0; i < MAXNAMLEN; i++) 2687 input_path[input_pathp][i] = '\0'; 2688 for (;;) { 2689 c = getachar(); 2690 if (c == '\\') { 2691 if ((int)strlen(input_path[input_pathp]) + 1 >= MAXNAMLEN) { 2692 printf("maximum name length exceeded, "); 2693 printf("truncating\n"); 2694 return; 2695 } 2696 input_path[input_pathp][strlen(input_path[input_pathp])] = c; 2697 input_path[input_pathp][strlen(input_path[input_pathp])] = 2698 getachar(); 2699 continue; 2700 } 2701 if (c == ' ' || c == '\n') { 2702 ungetachar(c); 2703 return; 2704 } 2705 if (!doing_find && c == '/') { 2706 if (++input_pathp >= MAXPATHLEN) { 2707 printf("maximum path length exceeded, "); 2708 printf("truncating\n"); 2709 input_pathp--; 2710 return; 2711 } 2712 goto clear; 2713 } 2714 if ((int)strlen(input_path[input_pathp]) >= MAXNAMLEN) { 2715 printf("maximum name length exceeded, truncating\n"); 2716 return; 2717 } 2718 input_path[input_pathp][strlen(input_path[input_pathp])] = c; 2719 } 2720 } 2721 2722 /* 2723 * compare - check if a filename matches the pattern entered by the user. 2724 * Handles '*', '?', and '[]'. 2725 */ 2726 static int 2727 compare(s1, s2, at_start) 2728 char *s1, *s2; 2729 short at_start; 2730 { 2731 register char c, *s; 2732 2733 s = s2; 2734 while ((c = *s1) != NULL) { 2735 if (c == '*') { 2736 if (at_start && s == s2 && !letter(*s2) && !digit(*s2)) 2737 return (0); 2738 if (*++s1 == 0) 2739 return (1); 2740 while (*s2) { 2741 if (compare(s1, s2, 0)) 2742 return (1); 2743 if (error) 2744 return (0); 2745 s2++; 2746 } 2747 } 2748 if (*s2 == 0) 2749 return (0); 2750 if (c == '\\') { 2751 s1++; 2752 goto compare_chars; 2753 } 2754 if (c == '?') { 2755 if (at_start && s == s2 && !letter(*s2) && !digit(*s2)) 2756 return (0); 2757 s1++; 2758 s2++; 2759 continue; 2760 } 2761 if (c == '[') { 2762 s1++; 2763 if (*s2 >= *s1++) { 2764 if (*s1++ != '-') { 2765 printf("missing '-'\n"); 2766 error++; 2767 return (0); 2768 } 2769 if (*s2 <= *s1++) { 2770 if (*s1++ != ']') { 2771 printf("missing ']'"); 2772 error++; 2773 return (0); 2774 } 2775 s2++; 2776 continue; 2777 } 2778 } 2779 } 2780 compare_chars: 2781 if (*s1++ == *s2++) 2782 continue; 2783 else 2784 return (0); 2785 } 2786 if (*s1 == *s2) 2787 return (1); 2788 return (0); 2789 } 2790 2791 /* 2792 * freemem - free the memory allocated to the filenames structure. 2793 */ 2794 static void 2795 freemem(p, numb) 2796 struct filenames *p; 2797 int numb; 2798 { 2799 register int i, j; 2800 2801 if (numb == 0) 2802 return; 2803 for (i = 0; i < numb; i++, p++) { 2804 for (j = 0; j <= p->len; j++) 2805 free(p->fname[j]); 2806 free((char *)p->fname); 2807 } 2808 } 2809 2810 /* 2811 * print_path - print the pathname held in p. 2812 */ 2813 static void 2814 print_path(p, pntr) 2815 char *p[]; 2816 int pntr; 2817 { 2818 register int i; 2819 2820 printf("/"); 2821 if (pntr >= 0) { 2822 for (i = 0; i < pntr; i++) 2823 printf("%s/", p[i]); 2824 printf("%s", p[pntr]); 2825 } 2826 } 2827 2828 /* 2829 * fill - fill a section with a value or string. 2830 * addr,count:fill=[value, "string"]. 2831 */ 2832 static void 2833 fill() 2834 { 2835 register char *cptr; 2836 register int i; 2837 short eof_flag, end = 0, eof = 0; 2838 long temp, tcount; 2839 u_offset_t taddr; 2840 2841 if (wrtflag == O_RDONLY) { 2842 printf("not opened for write '-w'\n"); 2843 error++; 2844 return; 2845 } 2846 temp = expr(); 2847 if (error) 2848 return; 2849 if ((cptr = getblk(addr)) == 0) 2850 return; 2851 if (type == NUMB) 2852 eof_flag = 0; 2853 else 2854 eof_flag = 1; 2855 taddr = addr; 2856 switch (objsz) { 2857 case LONG: 2858 addr &= ~(LONG - 1); 2859 break; 2860 case SHORT: 2861 addr &= ~(SHORT - 1); 2862 temp &= 0177777L; 2863 break; 2864 case CHAR: 2865 temp &= 0377; 2866 } 2867 cur_bytes -= taddr - addr; 2868 cptr += blkoff(fs, addr); 2869 tcount = check_addr(eof_flag, &end, &eof, 0); 2870 for (i = 0; i < tcount; i++) { 2871 switch (objsz) { 2872 case LONG: 2873 /*LINTED*/ 2874 *(long *)cptr = temp; 2875 break; 2876 case SHORT: 2877 /*LINTED*/ 2878 *(short *)cptr = temp; 2879 break; 2880 case CHAR: 2881 *cptr = temp; 2882 } 2883 cptr += objsz; 2884 } 2885 addr += (tcount - 1) * objsz; 2886 cur_bytes += (tcount - 1) * objsz; 2887 put((u_offset_t)temp, objsz); 2888 if (eof) { 2889 printf("end of file\n"); 2890 error++; 2891 } else if (end) { 2892 printf("end of block\n"); 2893 error++; 2894 } 2895 } 2896 2897 /* 2898 * get - read a byte, short or long from the file system. 2899 * The entire block containing the desired item is read 2900 * and the appropriate data is extracted and returned. 2901 */ 2902 static offset_t 2903 get(lngth) 2904 short lngth; 2905 { 2906 2907 register char *bptr; 2908 u_offset_t temp = addr; 2909 2910 objsz = lngth; 2911 if (objsz == INODE || objsz == SHORT) 2912 temp &= ~(SHORT - 1); 2913 else if (objsz == DIRECTORY || objsz == LONG || objsz == SHADOW_DATA) 2914 temp &= ~(LONG - 1); 2915 if ((bptr = getblk(temp)) == 0) 2916 return (-1); 2917 bptr += blkoff(fs, temp); 2918 switch (objsz) { 2919 case CHAR: 2920 return ((offset_t)*bptr); 2921 case SHORT: 2922 case INODE: 2923 /*LINTED*/ 2924 return ((offset_t)(*(short *)bptr)); 2925 case LONG: 2926 case DIRECTORY: 2927 case SHADOW_DATA: 2928 /*LINTED*/ 2929 return ((offset_t)(*(long *)bptr)); 2930 case U_OFFSET_T: 2931 /*LINTED*/ 2932 return (*(offset_t *)bptr); 2933 } 2934 return (0); 2935 } 2936 2937 /* 2938 * cgrp_check - make sure that we don't bump the cylinder group 2939 * beyond the total number of cylinder groups or before the start. 2940 */ 2941 static int 2942 cgrp_check(cgrp) 2943 long cgrp; 2944 { 2945 if (cgrp < 0) { 2946 if (objsz == CGRP) 2947 printf("beginning of cylinder groups\n"); 2948 else 2949 printf("beginning of super blocks\n"); 2950 error++; 2951 return (0); 2952 } 2953 if (cgrp >= fs->fs_ncg) { 2954 if (objsz == CGRP) 2955 printf("end of cylinder groups\n"); 2956 else 2957 printf("end of super blocks\n"); 2958 error++; 2959 return (0); 2960 } 2961 if (objsz == CGRP) 2962 return (cgtod(fs, cgrp) << FRGSHIFT); 2963 else 2964 return (cgsblock(fs, cgrp) << FRGSHIFT); 2965 } 2966 2967 /* 2968 * icheck - make sure we can read the block containing the inode 2969 * and determine the filesize (0 if inode not allocated). Return 2970 * 0 if error otherwise return the mode. 2971 */ 2972 icheck(address) 2973 u_offset_t address; 2974 { 2975 register char *cptr; 2976 register struct dinode *ip; 2977 2978 if ((cptr = getblk(address)) == 0) 2979 return (0); 2980 cptr += blkoff(fs, address); 2981 /*LINTED*/ 2982 ip = (struct dinode *)cptr; 2983 if ((ip->di_mode & IFMT) == 0) { 2984 if (!override) { 2985 printf("inode not allocated\n"); 2986 error++; 2987 return (0); 2988 } 2989 blocksize = filesize = 0; 2990 } else { 2991 trapped++; 2992 filesize = ip->di_size; 2993 blocksize = filesize * 2; 2994 } 2995 return (ip->di_mode); 2996 } 2997 2998 /* 2999 * getdirslot - get the address of the directory slot desired. 3000 */ 3001 static u_offset_t 3002 getdirslot(slot) 3003 long slot; 3004 { 3005 register char *cptr; 3006 register struct direct *dirp; 3007 register short i; 3008 char *string = &scratch[0]; 3009 short bod = 0, mode, temp; 3010 3011 if (slot < 0) { 3012 slot = 0; 3013 bod++; 3014 } 3015 if (type != DIRECTORY) { 3016 if (type == BLOCK) 3017 string = "block"; 3018 else 3019 string = "fragment"; 3020 addr = bod_addr; 3021 if ((cptr = getblk(addr)) == 0) 3022 return (0); 3023 cptr += blkoff(fs, addr); 3024 cur_bytes = 0; 3025 /*LINTED*/ 3026 dirp = (struct direct *)cptr; 3027 for (dirslot = 0; dirslot < slot; dirslot++) { 3028 /*LINTED*/ 3029 dirp = (struct direct *)cptr; 3030 if (blocksize > filesize) { 3031 if (cur_bytes + (long)dirp->d_reclen >= 3032 filesize) { 3033 printf("end of file\n"); 3034 erraddr = addr; 3035 errcur_bytes = cur_bytes; 3036 stringsize = STRINGSIZE(dirp); 3037 error++; 3038 return (addr); 3039 } 3040 } else { 3041 if (cur_bytes + (long)dirp->d_reclen >= 3042 blocksize) { 3043 printf("end of %s\n", string); 3044 erraddr = addr; 3045 errcur_bytes = cur_bytes; 3046 stringsize = STRINGSIZE(dirp); 3047 error++; 3048 return (addr); 3049 } 3050 } 3051 cptr += dirp->d_reclen; 3052 addr += dirp->d_reclen; 3053 cur_bytes += dirp->d_reclen; 3054 } 3055 if (bod) { 3056 if (blocksize > filesize) 3057 printf("beginning of file\n"); 3058 else 3059 printf("beginning of %s\n", string); 3060 erraddr = addr; 3061 errcur_bytes = cur_bytes; 3062 error++; 3063 } 3064 stringsize = STRINGSIZE(dirp); 3065 return (addr); 3066 } else { 3067 addr = cur_ino; 3068 if ((mode = icheck(addr)) == 0) 3069 return (0); 3070 if (!override && (mode & IFDIR) == 0) { 3071 printf("inode is not a directory\n"); 3072 error++; 3073 return (0); 3074 } 3075 temp = slot; 3076 i = cur_bytes = 0; 3077 for (;;) { 3078 if (i == 0 || bcomp(addr)) { 3079 error = 0; 3080 if ((addr = (bmap((long)i++) << FRGSHIFT)) == 0) 3081 break; 3082 if ((cptr = getblk(addr)) == 0) 3083 break; 3084 cptr += blkoff(fs, addr); 3085 } 3086 /*LINTED*/ 3087 dirp = (struct direct *)cptr; 3088 value = dirp->d_ino; 3089 if (!temp--) 3090 break; 3091 if (cur_bytes + (long)dirp->d_reclen >= filesize) { 3092 printf("end of file\n"); 3093 dirslot = slot - temp - 1; 3094 objsz = DIRECTORY; 3095 erraddr = addr; 3096 errcur_bytes = cur_bytes; 3097 stringsize = STRINGSIZE(dirp); 3098 error++; 3099 return (addr); 3100 } 3101 addr += dirp->d_reclen; 3102 cptr += dirp->d_reclen; 3103 cur_bytes += dirp->d_reclen; 3104 } 3105 dirslot = slot; 3106 objsz = DIRECTORY; 3107 if (bod) { 3108 printf("beginning of file\n"); 3109 erraddr = addr; 3110 errcur_bytes = cur_bytes; 3111 error++; 3112 } 3113 stringsize = STRINGSIZE(dirp); 3114 return (addr); 3115 } 3116 } 3117 3118 3119 /* 3120 * getshadowslot - get the address of the shadow data desired 3121 */ 3122 static int 3123 getshadowslot(shadow) 3124 long shadow; 3125 { 3126 struct ufs_fsd fsd; 3127 short bod = 0, mode; 3128 long taddr, tcurbytes; 3129 3130 if (shadow < 0) { 3131 shadow = 0; 3132 bod++; 3133 } 3134 if (type != SHADOW_DATA) { 3135 if (shadow < cur_shad) { 3136 printf("can't scan shadow data in reverse\n"); 3137 error++; 3138 return (0); 3139 } 3140 } else { 3141 addr = cur_ino; 3142 if ((mode = icheck(addr)) == 0) 3143 return (0); 3144 if (!override && (mode & IFMT) != IFSHAD) { 3145 printf("inode is not a shadow\n"); 3146 error++; 3147 return (0); 3148 } 3149 cur_bytes = 0; 3150 cur_shad = 0; 3151 syncshadowscan(1); /* force synchronization */ 3152 } 3153 3154 for (; cur_shad < shadow; cur_shad++) { 3155 taddr = addr; 3156 tcurbytes = cur_bytes; 3157 getshadowdata((long *)&fsd, LONG + LONG); 3158 addr = taddr; 3159 cur_bytes = tcurbytes; 3160 if (cur_bytes + (long)fsd.fsd_size > filesize) { 3161 syncshadowscan(0); 3162 printf("end of file\n"); 3163 erraddr = addr; 3164 errcur_bytes = cur_bytes; 3165 error++; 3166 return (addr); 3167 } 3168 addr += fsd.fsd_size; 3169 cur_bytes += fsd.fsd_size; 3170 syncshadowscan(0); 3171 } 3172 if (type == SHADOW_DATA) 3173 objsz = SHADOW_DATA; 3174 if (bod) { 3175 printf("beginning of file\n"); 3176 erraddr = addr; 3177 errcur_bytes = cur_bytes; 3178 error++; 3179 } 3180 return (addr); 3181 } 3182 3183 static void 3184 getshadowdata(buf, len) 3185 long *buf; 3186 int len; 3187 { 3188 long tfsd; 3189 3190 len /= LONG; 3191 for (tfsd = 0; tfsd < len; tfsd++) { 3192 buf[tfsd] = get(SHADOW_DATA); 3193 addr += LONG; 3194 cur_bytes += LONG; 3195 syncshadowscan(0); 3196 } 3197 } 3198 3199 static void 3200 syncshadowscan(force) 3201 int force; 3202 { 3203 long curblkoff; 3204 if (type == SHADOW_DATA && (force || 3205 lblkno(fs, addr) != (bhdr.fwd)->blkno)) { 3206 curblkoff = blkoff(fs, cur_bytes); 3207 addr = bmap(lblkno(fs, cur_bytes)) << FRGSHIFT; 3208 addr += curblkoff; 3209 cur_bytes += curblkoff; 3210 (void) getblk(addr); 3211 objsz = SHADOW_DATA; 3212 } 3213 } 3214 3215 3216 3217 /* 3218 * putf - print a byte as an ascii character if possible. 3219 * The exceptions are tabs, newlines, backslashes 3220 * and nulls which are printed as the standard C 3221 * language escapes. Characters which are not 3222 * recognized are printed as \?. 3223 */ 3224 static void 3225 putf(c) 3226 register char c; 3227 { 3228 3229 if (c <= 037 || c >= 0177 || c == '\\') { 3230 printf("\\"); 3231 switch (c) { 3232 case '\\': 3233 printf("\\"); 3234 break; 3235 case '\t': 3236 printf("t"); 3237 break; 3238 case '\n': 3239 printf("n"); 3240 break; 3241 case '\0': 3242 printf("0"); 3243 break; 3244 default: 3245 printf("?"); 3246 } 3247 } else { 3248 printf("%c", c); 3249 printf(" "); 3250 } 3251 } 3252 3253 /* 3254 * put - write an item into the buffer for the current address 3255 * block. The value is checked to make sure that it will 3256 * fit in the size given without truncation. If successful, 3257 * the entire block is written back to the file system. 3258 */ 3259 static void 3260 put(item, lngth) 3261 u_offset_t item; 3262 short lngth; 3263 { 3264 3265 register char *bptr, *sbptr; 3266 long s_err, nbytes; 3267 long olditem; 3268 3269 if (wrtflag == O_RDONLY) { 3270 printf("not opened for write '-w'\n"); 3271 error++; 3272 return; 3273 } 3274 objsz = lngth; 3275 if ((sbptr = getblk(addr)) == 0) 3276 return; 3277 bptr = sbptr + blkoff(fs, addr); 3278 switch (objsz) { 3279 case LONG: 3280 case DIRECTORY: 3281 /*LINTED*/ 3282 olditem = *(long *)bptr; 3283 /*LINTED*/ 3284 *(long *)bptr = item; 3285 break; 3286 case SHORT: 3287 case INODE: 3288 /*LINTED*/ 3289 olditem = (long)*(short *)bptr; 3290 item &= 0177777L; 3291 /*LINTED*/ 3292 *(short *)bptr = item; 3293 break; 3294 case CHAR: 3295 olditem = (long)*bptr; 3296 item &= 0377; 3297 *bptr = lobyte(loword(item)); 3298 break; 3299 default: 3300 error++; 3301 return; 3302 } 3303 if ((s_err = llseek(fd, (offset_t)(addr & fs->fs_bmask), 0)) == -1) { 3304 error++; 3305 printf("seek error : %" PRIx64 "\n", addr); 3306 return; 3307 } 3308 if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) { 3309 error++; 3310 printf("write error : addr = %" PRIx64 "\n", addr); 3311 printf(" : s_err = %lx\n", s_err); 3312 printf(" : nbytes = %lx\n", nbytes); 3313 return; 3314 } 3315 if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) { 3316 index(base); 3317 print(olditem, 8, -8, 0); 3318 printf("\t=\t"); 3319 print(item, 8, -8, 0); 3320 printf("\n"); 3321 } else { 3322 if (objsz == DIRECTORY) { 3323 addr = cur_dir; 3324 fprnt('?', 'd'); 3325 } else { 3326 addr = cur_ino; 3327 objsz = INODE; 3328 fprnt('?', 'i'); 3329 } 3330 } 3331 } 3332 3333 /* 3334 * getblk - check if the desired block is in the file system. 3335 * Search the incore buffers to see if the block is already 3336 * available. If successful, unlink the buffer control block 3337 * from its position in the buffer list and re-insert it at 3338 * the head of the list. If failure, use the last buffer 3339 * in the list for the desired block. Again, this control 3340 * block is placed at the head of the list. This process 3341 * will leave commonly requested blocks in the in-core buffers. 3342 * Finally, a pointer to the buffer is returned. 3343 */ 3344 static char * 3345 getblk(address) 3346 u_offset_t address; 3347 { 3348 3349 register struct lbuf *bp; 3350 long s_err, nbytes; 3351 unsigned long block; 3352 3353 read_requests++; 3354 block = lblkno(fs, address); 3355 if (block >= fragstoblks(fs, fs->fs_size)) { 3356 printf("cannot read block %lu\n", block); 3357 error++; 3358 return (0); 3359 } 3360 for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd) 3361 if (bp->valid && bp->blkno == block) 3362 goto xit; 3363 actual_disk_reads++; 3364 bp = bhdr.back; 3365 bp->blkno = block; 3366 bp->valid = 0; 3367 if ((s_err = llseek(fd, (offset_t)(address & fs->fs_bmask), 0)) == -1) { 3368 error++; 3369 printf("seek error : %" PRIx64 "\n", address); 3370 return (0); 3371 } 3372 if ((nbytes = read(fd, bp->blkaddr, BLKSIZE)) != BLKSIZE) { 3373 error++; 3374 printf("read error : addr = %" PRIx64 "\n", address); 3375 printf(" : s_err = %lx\n", s_err); 3376 printf(" : nbytes = %lx\n", nbytes); 3377 return (0); 3378 } 3379 bp->valid++; 3380 xit: bp->back->fwd = bp->fwd; 3381 bp->fwd->back = bp->back; 3382 insert(bp); 3383 return (bp->blkaddr); 3384 } 3385 3386 /* 3387 * insert - place the designated buffer control block 3388 * at the head of the linked list of buffers. 3389 */ 3390 static void 3391 insert(bp) 3392 register struct lbuf *bp; 3393 { 3394 3395 bp->back = &bhdr; 3396 bp->fwd = bhdr.fwd; 3397 bhdr.fwd->back = bp; 3398 bhdr.fwd = bp; 3399 } 3400 3401 /* 3402 * err - called on interrupts. Set the current address 3403 * back to the last address stored in erraddr. Reset all 3404 * appropriate flags. A reset call is made to return 3405 * to the main loop; 3406 */ 3407 #ifdef sun 3408 /*ARGSUSED*/ 3409 static void 3410 err(sig) 3411 int sig; 3412 #else 3413 err() 3414 #endif /* sun */ 3415 { 3416 freemem(filenames, nfiles); 3417 nfiles = 0; 3418 (void) signal(2, err); 3419 addr = erraddr; 3420 cur_ino = errino; 3421 cur_inum = errinum; 3422 cur_bytes = errcur_bytes; 3423 error = 0; 3424 c_count = 0; 3425 printf("\n?\n"); 3426 (void) fseek(stdin, 0L, 2); 3427 longjmp(env, 0); 3428 } 3429 3430 /* 3431 * devcheck - check that the given mode represents a 3432 * special device. The IFCHR bit is on for both 3433 * character and block devices. 3434 */ 3435 static int 3436 devcheck(md) 3437 register short md; 3438 { 3439 if (override) 3440 return (0); 3441 switch (md & IFMT) { 3442 case IFCHR: 3443 case IFBLK: 3444 return (0); 3445 } 3446 3447 printf("not character or block device\n"); 3448 error++; 3449 return (1); 3450 } 3451 3452 /* 3453 * nullblk - return error if address is zero. This is done 3454 * to prevent block 0 from being used as an indirect block 3455 * for a large file or as a data block for a small file. 3456 */ 3457 static int 3458 nullblk(bn) 3459 long bn; 3460 { 3461 if (bn != 0) 3462 return (0); 3463 printf("non existent block\n"); 3464 error++; 3465 return (1); 3466 } 3467 3468 /* 3469 * puta - put ascii characters into a buffer. The string 3470 * terminates with a quote or newline. The leading quote, 3471 * which is optional for directory names, was stripped off 3472 * by the assignment case in the main loop. 3473 */ 3474 static void 3475 puta() 3476 { 3477 register char *cptr, c; 3478 register int i; 3479 char *sbptr; 3480 short terror = 0; 3481 long maxchars, s_err, nbytes, temp; 3482 u_offset_t taddr = addr; 3483 long tcount = 0, item, olditem = 0; 3484 3485 if (wrtflag == O_RDONLY) { 3486 printf("not opened for write '-w'\n"); 3487 error++; 3488 return; 3489 } 3490 if ((sbptr = getblk(addr)) == 0) 3491 return; 3492 cptr = sbptr + blkoff(fs, addr); 3493 if (objsz == DIRECTORY) { 3494 if (acting_on_directory) 3495 maxchars = stringsize - 1; 3496 else 3497 maxchars = LONG; 3498 } else if (objsz == INODE) 3499 maxchars = objsz - (addr - cur_ino); 3500 else 3501 maxchars = min(blocksize - cur_bytes, filesize - cur_bytes); 3502 while ((c = getachar()) != '"') { 3503 if (tcount >= maxchars) { 3504 printf("string too long\n"); 3505 if (objsz == DIRECTORY) 3506 addr = cur_dir; 3507 else if (acting_on_inode || objsz == INODE) 3508 addr = cur_ino; 3509 else 3510 addr = taddr; 3511 erraddr = addr; 3512 errcur_bytes = cur_bytes; 3513 terror++; 3514 break; 3515 } 3516 tcount++; 3517 if (c == '\n') { 3518 ungetachar(c); 3519 break; 3520 } 3521 temp = (long)*cptr; 3522 olditem <<= BITSPERCHAR; 3523 olditem += temp & 0xff; 3524 if (c == '\\') { 3525 switch (c = getachar()) { 3526 case 't': 3527 *cptr++ = '\t'; 3528 break; 3529 case 'n': 3530 *cptr++ = '\n'; 3531 break; 3532 case '0': 3533 *cptr++ = '\0'; 3534 break; 3535 default: 3536 *cptr++ = c; 3537 break; 3538 } 3539 } 3540 else 3541 *cptr++ = c; 3542 } 3543 if (objsz == DIRECTORY && acting_on_directory) 3544 for (i = tcount; i <= maxchars; i++) 3545 *cptr++ = '\0'; 3546 if ((s_err = llseek(fd, (offset_t)(addr & fs->fs_bmask), 0)) == -1) { 3547 error++; 3548 printf("seek error : %" PRIx64 "\n", addr); 3549 return; 3550 } 3551 if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) { 3552 error++; 3553 printf("write error : addr = %" PRIx64 "\n", addr); 3554 printf(" : s_err = %lx\n", s_err); 3555 printf(" : nbytes = %lx\n", nbytes); 3556 return; 3557 } 3558 if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) { 3559 addr += tcount; 3560 cur_bytes += tcount; 3561 taddr = addr; 3562 if (objsz != CHAR) { 3563 addr &= ~(objsz - 1); 3564 cur_bytes -= taddr - addr; 3565 } 3566 if (addr == taddr) { 3567 addr -= objsz; 3568 taddr = addr; 3569 } 3570 tcount = LONG - (taddr - addr); 3571 index(base); 3572 if ((cptr = getblk(addr)) == 0) 3573 return; 3574 cptr += blkoff(fs, addr); 3575 switch (objsz) { 3576 case LONG: 3577 /*LINTED*/ 3578 item = *(long *)cptr; 3579 if (tcount < LONG) { 3580 olditem <<= tcount * BITSPERCHAR; 3581 temp = 1; 3582 for (i = 0; i < (tcount*BITSPERCHAR); i++) 3583 temp <<= 1; 3584 olditem += item & (temp - 1); 3585 } 3586 break; 3587 case SHORT: 3588 /*LINTED*/ 3589 item = (long)*(short *)cptr; 3590 if (tcount < SHORT) { 3591 olditem <<= tcount * BITSPERCHAR; 3592 temp = 1; 3593 for (i = 0; i < (tcount * BITSPERCHAR); i++) 3594 temp <<= 1; 3595 olditem += item & (temp - 1); 3596 } 3597 olditem &= 0177777L; 3598 break; 3599 case CHAR: 3600 item = (long)*cptr; 3601 olditem &= 0377; 3602 } 3603 print(olditem, 8, -8, 0); 3604 printf("\t=\t"); 3605 print(item, 8, -8, 0); 3606 printf("\n"); 3607 } else { 3608 if (objsz == DIRECTORY) { 3609 addr = cur_dir; 3610 fprnt('?', 'd'); 3611 } else { 3612 addr = cur_ino; 3613 objsz = INODE; 3614 fprnt('?', 'i'); 3615 } 3616 } 3617 if (terror) 3618 error++; 3619 } 3620 3621 /* 3622 * fprnt - print data. 'count' elements are printed where '*' will 3623 * print an entire blocks worth or up to the eof, whichever 3624 * occurs first. An error will occur if crossing a block boundary 3625 * is attempted since consecutive blocks don't usually have 3626 * meaning. Current print types: 3627 * / b - print as bytes (base sensitive) 3628 * c - print as characters 3629 * o O - print as octal shorts (longs) 3630 * d D - print as decimal shorts (longs) 3631 * x X - print as hexadecimal shorts (longs) 3632 * ? c - print as cylinder groups 3633 * d - print as directories 3634 * i - print as inodes 3635 * s - print as super blocks 3636 * S - print as shadow data 3637 */ 3638 static void 3639 fprnt(style, po) 3640 register char style, po; 3641 { 3642 register int i; 3643 register struct fs *sb; 3644 register struct cg *cg; 3645 register struct direct *dirp; 3646 register struct dinode *ip; 3647 int tbase; 3648 char c, *cptr, *p; 3649 long tinode, tcount, temp; 3650 u_offset_t taddr; 3651 short offset, mode, end = 0, eof = 0, eof_flag; 3652 unsigned short *sptr; 3653 unsigned long *lptr; 3654 offset_t curoff, curioff; 3655 3656 laststyle = style; 3657 lastpo = po; 3658 should_print = 0; 3659 if (count != 1) { 3660 if (clear) { 3661 count = 1; 3662 star = 0; 3663 clear = 0; 3664 } else 3665 clear = 1; 3666 } 3667 tcount = count; 3668 offset = blkoff(fs, addr); 3669 3670 if (style == '/') { 3671 if (type == NUMB) 3672 eof_flag = 0; 3673 else 3674 eof_flag = 1; 3675 switch (po) { 3676 3677 case 'c': /* print as characters */ 3678 case 'b': /* or bytes */ 3679 if ((cptr = getblk(addr)) == 0) 3680 return; 3681 cptr += offset; 3682 objsz = CHAR; 3683 tcount = check_addr(eof_flag, &end, &eof, 0); 3684 if (tcount) { 3685 for (i = 0; tcount--; i++) { 3686 if (i % 16 == 0) { 3687 if (i) 3688 printf("\n"); 3689 index(base); 3690 } 3691 if (po == 'c') { 3692 putf(*cptr++); 3693 if ((i + 1) % 16) 3694 printf(" "); 3695 } else { 3696 if ((i + 1) % 16 == 0) 3697 print(*cptr++ & 0377L, 3698 2, -2, 0); 3699 else 3700 print(*cptr++ & 0377L, 3701 4, -2, 0); 3702 } 3703 addr += CHAR; 3704 cur_bytes += CHAR; 3705 } 3706 printf("\n"); 3707 } 3708 addr -= CHAR; 3709 erraddr = addr; 3710 cur_bytes -= CHAR; 3711 errcur_bytes = cur_bytes; 3712 if (eof) { 3713 printf("end of file\n"); 3714 error++; 3715 } else if (end) { 3716 if (type == BLOCK) 3717 printf("end of block\n"); 3718 else 3719 printf("end of fragment\n"); 3720 error++; 3721 } 3722 return; 3723 3724 case 'o': /* print as octal shorts */ 3725 tbase = OCTAL; 3726 goto otx; 3727 case 'd': /* print as decimal shorts */ 3728 tbase = DECIMAL; 3729 goto otx; 3730 case 'x': /* print as hex shorts */ 3731 tbase = HEX; 3732 otx: 3733 if ((cptr = getblk(addr)) == 0) 3734 return; 3735 taddr = addr; 3736 addr &= ~(SHORT - 1); 3737 cur_bytes -= taddr - addr; 3738 cptr += blkoff(fs, addr); 3739 /*LINTED*/ 3740 sptr = (unsigned short *)cptr; 3741 objsz = SHORT; 3742 tcount = check_addr(eof_flag, &end, &eof, 0); 3743 if (tcount) { 3744 for (i = 0; tcount--; i++) { 3745 sptr = (unsigned short *)print_check( 3746 /*LINTED*/ 3747 (unsigned long *)sptr, 3748 &tcount, tbase, i); 3749 switch (po) { 3750 case 'o': 3751 printf("%06o ", *sptr++); 3752 break; 3753 case 'd': 3754 printf("%05d ", *sptr++); 3755 break; 3756 case 'x': 3757 printf("%04x ", *sptr++); 3758 } 3759 addr += SHORT; 3760 cur_bytes += SHORT; 3761 } 3762 printf("\n"); 3763 } 3764 addr -= SHORT; 3765 erraddr = addr; 3766 cur_bytes -= SHORT; 3767 errcur_bytes = cur_bytes; 3768 if (eof) { 3769 printf("end of file\n"); 3770 error++; 3771 } else if (end) { 3772 if (type == BLOCK) 3773 printf("end of block\n"); 3774 else 3775 printf("end of fragment\n"); 3776 error++; 3777 } 3778 return; 3779 3780 case 'O': /* print as octal longs */ 3781 tbase = OCTAL; 3782 goto OTX; 3783 case 'D': /* print as decimal longs */ 3784 tbase = DECIMAL; 3785 goto OTX; 3786 case 'X': /* print as hex longs */ 3787 tbase = HEX; 3788 OTX: 3789 if ((cptr = getblk(addr)) == 0) 3790 return; 3791 taddr = addr; 3792 addr &= ~(LONG - 1); 3793 cur_bytes -= taddr - addr; 3794 cptr += blkoff(fs, addr); 3795 /*LINTED*/ 3796 lptr = (unsigned long *)cptr; 3797 objsz = LONG; 3798 tcount = check_addr(eof_flag, &end, &eof, 0); 3799 if (tcount) { 3800 for (i = 0; tcount--; i++) { 3801 lptr = print_check(lptr, &tcount, 3802 tbase, i); 3803 switch (po) { 3804 case 'O': 3805 printf("%011lo ", *lptr++); 3806 break; 3807 case 'D': 3808 printf("%010lu ", *lptr++); 3809 break; 3810 case 'X': 3811 printf("%08lx ", *lptr++); 3812 } 3813 addr += LONG; 3814 cur_bytes += LONG; 3815 } 3816 printf("\n"); 3817 } 3818 addr -= LONG; 3819 erraddr = addr; 3820 cur_bytes -= LONG; 3821 errcur_bytes = cur_bytes; 3822 if (eof) { 3823 printf("end of file\n"); 3824 error++; 3825 } else if (end) { 3826 if (type == BLOCK) 3827 printf("end of block\n"); 3828 else 3829 printf("end of fragment\n"); 3830 error++; 3831 } 3832 return; 3833 3834 default: 3835 error++; 3836 printf("no such print option\n"); 3837 return; 3838 } 3839 } else 3840 switch (po) { 3841 3842 case 'c': /* print as cylinder group */ 3843 if (type != NUMB) 3844 if (cur_cgrp + count > fs->fs_ncg) { 3845 tcount = fs->fs_ncg - cur_cgrp; 3846 if (!star) 3847 end++; 3848 } 3849 addr &= ~(LONG - 1); 3850 for (/* void */; tcount--; /* void */) { 3851 erraddr = addr; 3852 errcur_bytes = cur_bytes; 3853 if (type != NUMB) { 3854 addr = cgtod(fs, cur_cgrp) 3855 << FRGSHIFT; 3856 cur_cgrp++; 3857 } 3858 if ((cptr = getblk(addr)) == 0) { 3859 if (cur_cgrp) 3860 cur_cgrp--; 3861 return; 3862 } 3863 cptr += blkoff(fs, addr); 3864 /*LINTED*/ 3865 cg = (struct cg *)cptr; 3866 if (type == NUMB) { 3867 cur_cgrp = cg->cg_cgx + 1; 3868 type = objsz = CGRP; 3869 if (cur_cgrp + count - 1 > fs->fs_ncg) { 3870 tcount = fs->fs_ncg - cur_cgrp; 3871 if (!star) 3872 end++; 3873 } 3874 } 3875 if (! override && !cg_chkmagic(cg)) { 3876 printf("invalid cylinder group "); 3877 printf("magic word\n"); 3878 if (cur_cgrp) 3879 cur_cgrp--; 3880 error++; 3881 return; 3882 } 3883 printcg(cg); 3884 if (tcount) 3885 printf("\n"); 3886 } 3887 cur_cgrp--; 3888 if (end) { 3889 printf("end of cylinder groups\n"); 3890 error++; 3891 } 3892 return; 3893 3894 case 'd': /* print as directories */ 3895 if ((cptr = getblk(addr)) == 0) 3896 return; 3897 if (type == NUMB) { 3898 if (fragoff(fs, addr)) { 3899 printf("address must be at the "); 3900 printf("beginning of a fragment\n"); 3901 error++; 3902 return; 3903 } 3904 bod_addr = addr; 3905 type = FRAGMENT; 3906 dirslot = 0; 3907 cur_bytes = 0; 3908 blocksize = FRGSIZE; 3909 filesize = FRGSIZE * 2; 3910 } 3911 cptr += offset; 3912 objsz = DIRECTORY; 3913 while (tcount-- && cur_bytes < filesize && 3914 cur_bytes < blocksize && !bcomp(addr)) { 3915 /*LINTED*/ 3916 dirp = (struct direct *)cptr; 3917 tinode = dirp->d_ino; 3918 printf("i#: "); 3919 if (tinode == 0) 3920 printf("free\t"); 3921 else 3922 print(tinode, 12, -8, 0); 3923 printf("%s\n", &dirp->d_name[0]); 3924 erraddr = addr; 3925 errcur_bytes = cur_bytes; 3926 addr += dirp->d_reclen; 3927 cptr += dirp->d_reclen; 3928 cur_bytes += dirp->d_reclen; 3929 dirslot++; 3930 stringsize = STRINGSIZE(dirp); 3931 } 3932 addr = erraddr; 3933 cur_dir = addr; 3934 cur_bytes = errcur_bytes; 3935 dirslot--; 3936 if (tcount >= 0 && !star) { 3937 switch (type) { 3938 case FRAGMENT: 3939 printf("end of fragment\n"); 3940 break; 3941 case BLOCK: 3942 printf("end of block\n"); 3943 break; 3944 default: 3945 printf("end of directory\n"); 3946 } 3947 error++; 3948 } else 3949 error = 0; 3950 return; 3951 3952 case 'i': /* print as inodes */ 3953 /*LINTED*/ 3954 if ((ip = (struct dinode *)getblk(addr)) == 0) 3955 return; 3956 for (i = 1; i < fs->fs_ncg; i++) 3957 if (addr < (cgimin(fs, i) << FRGSHIFT)) 3958 break; 3959 i--; 3960 offset /= INODE; 3961 temp = (addr - (cgimin(fs, i) << FRGSHIFT)) >> FRGSHIFT; 3962 temp = (i * fs->fs_ipg) + fragstoblks(fs, temp) * 3963 INOPB(fs) + offset; 3964 if (count + offset > INOPB(fs)) { 3965 tcount = INOPB(fs) - offset; 3966 if (!star) 3967 end++; 3968 } 3969 objsz = INODE; 3970 ip += offset; 3971 for (i = 0; tcount--; ip++, temp++) { 3972 if ((mode = icheck(addr)) == 0) 3973 if (!override) 3974 continue; 3975 p = " ugtrwxrwxrwx"; 3976 3977 switch (mode & IFMT) { 3978 case IFDIR: 3979 c = 'd'; 3980 break; 3981 case IFCHR: 3982 c = 'c'; 3983 break; 3984 case IFBLK: 3985 c = 'b'; 3986 break; 3987 case IFREG: 3988 c = '-'; 3989 break; 3990 case IFLNK: 3991 c = 'l'; 3992 break; 3993 case IFSOCK: 3994 c = 's'; 3995 break; 3996 case IFSHAD: 3997 c = 'S'; 3998 break; 3999 case IFATTRDIR: 4000 c = 'A'; 4001 break; 4002 default: 4003 c = '?'; 4004 if (!override) 4005 goto empty; 4006 4007 } 4008 printf("i#: "); 4009 print(temp, 12, -8, 0); 4010 printf(" md: "); 4011 printf("%c", c); 4012 for (mode = mode << 4; *++p; mode = mode << 1) { 4013 if (mode & IFREG) 4014 printf("%c", *p); 4015 else 4016 printf("-"); 4017 } 4018 printf(" uid: "); 4019 print(ip->di_uid, 8, -4, 0); 4020 printf(" gid: "); 4021 print(ip->di_gid, 8, -4, 0); 4022 printf("\n"); 4023 printf("ln: "); 4024 print((long)ip->di_nlink, 8, -4, 0); 4025 printf(" bs: "); 4026 print(ip->di_blocks, 12, -8, 0); 4027 printf(" sz : "); 4028 printf("c_flags : "); 4029 print(ip->di_cflags, 12, -8, 0); 4030 #ifdef _LARGEFILE64_SOURCE 4031 printll(ip->di_size, 20, -16, 0); 4032 #else /* !_LARGEFILE64_SOURCE */ 4033 print(ip->di_size, 12, -8, 0); 4034 #endif /* _LARGEFILE64_SOURCE */ 4035 if (ip->di_shadow) { 4036 printf(" si: "); 4037 print(ip->di_shadow, 12, -8, 0); 4038 } 4039 printf("\n"); 4040 if (ip->di_oeftflag) { 4041 printf("ai: "); 4042 print(ip->di_oeftflag, 12, -8, 0); 4043 printf("\n"); 4044 } 4045 printf("\n"); 4046 switch (ip->di_mode & IFMT) { 4047 case IFBLK: 4048 case IFCHR: 4049 printf("maj: "); 4050 print(major(ip->di_ordev), 4, -2, 0); 4051 printf(" min: "); 4052 print(minor(ip->di_ordev), 4, -2, 0); 4053 printf("\n"); 4054 break; 4055 default: 4056 /* 4057 * only display blocks below the 4058 * current file size 4059 */ 4060 curoff = 0LL; 4061 for (i = 0; i < NDADDR; ) { 4062 if (ip->di_size <= curoff) 4063 break; 4064 printf("db#%x: ", i); 4065 print(ip->di_db[i], 11, -8, 0); 4066 4067 if (++i % 4 == 0) 4068 printf("\n"); 4069 else 4070 printf(" "); 4071 curoff += fs->fs_bsize; 4072 } 4073 if (i % 4) 4074 printf("\n"); 4075 4076 /* 4077 * curioff keeps track of the number 4078 * of bytes covered by each indirect 4079 * pointer in the inode, and is added 4080 * to curoff each time to get the 4081 * actual offset into the file. 4082 */ 4083 curioff = fs->fs_bsize * 4084 (fs->fs_bsize / sizeof (daddr_t)); 4085 for (i = 0; i < NIADDR; i++) { 4086 if (ip->di_size <= curoff) 4087 break; 4088 printf("ib#%x: ", i); 4089 print(ip->di_ib[i], 11, -8, 0); 4090 printf(" "); 4091 curoff += curioff; 4092 curioff *= (fs->fs_bsize / 4093 sizeof (daddr_t)); 4094 } 4095 if (i) 4096 printf("\n"); 4097 break; 4098 } 4099 if (count == 1) { 4100 time_t t; 4101 4102 t = ip->di_atime; 4103 printf("\taccessed: %s", ctime(&t)); 4104 t = ip->di_mtime; 4105 printf("\tmodified: %s", ctime(&t)); 4106 t = ip->di_ctime; 4107 printf("\tcreated : %s", ctime(&t)); 4108 } 4109 if (tcount) 4110 printf("\n"); 4111 empty: 4112 if (c == '?' && !override) { 4113 printf("i#: "); 4114 print(temp, 12, -8, 0); 4115 printf(" is unallocated\n"); 4116 if (count != 1) 4117 printf("\n"); 4118 } 4119 cur_ino = erraddr = addr; 4120 errcur_bytes = cur_bytes; 4121 cur_inum++; 4122 addr = addr + INODE; 4123 } 4124 addr = erraddr; 4125 cur_bytes = errcur_bytes; 4126 cur_inum--; 4127 if (end) { 4128 printf("end of block\n"); 4129 error++; 4130 } 4131 return; 4132 4133 case 's': /* print as super block */ 4134 if (cur_cgrp == -1) { 4135 addr = SBLOCK * DEV_BSIZE; 4136 type = NUMB; 4137 } 4138 addr &= ~(LONG - 1); 4139 if (type != NUMB) 4140 if (cur_cgrp + count > fs->fs_ncg) { 4141 tcount = fs->fs_ncg - cur_cgrp; 4142 if (!star) 4143 end++; 4144 } 4145 for (/* void */; tcount--; /* void */) { 4146 erraddr = addr; 4147 cur_bytes = errcur_bytes; 4148 if (type != NUMB) { 4149 addr = cgsblock(fs, cur_cgrp) 4150 << FRGSHIFT; 4151 cur_cgrp++; 4152 } 4153 if ((cptr = getblk(addr)) == 0) { 4154 if (cur_cgrp) 4155 cur_cgrp--; 4156 return; 4157 } 4158 cptr += blkoff(fs, addr); 4159 /*LINTED*/ 4160 sb = (struct fs *)cptr; 4161 if (type == NUMB) { 4162 for (i = 0; i < fs->fs_ncg; i++) 4163 if (addr == cgsblock(fs, i) << 4164 FRGSHIFT) 4165 break; 4166 if (i == fs->fs_ncg) 4167 cur_cgrp = 0; 4168 else 4169 cur_cgrp = i + 1; 4170 type = objsz = SB; 4171 if (cur_cgrp + count - 1 > fs->fs_ncg) { 4172 tcount = fs->fs_ncg - cur_cgrp; 4173 if (!star) 4174 end++; 4175 } 4176 } 4177 if ((sb->fs_magic != FS_MAGIC) && 4178 (sb->fs_magic != MTB_UFS_MAGIC)) { 4179 cur_cgrp = 0; 4180 if (!override) { 4181 printf("invalid super block "); 4182 printf("magic word\n"); 4183 cur_cgrp--; 4184 error++; 4185 return; 4186 } 4187 } 4188 if (sb->fs_magic == MTB_UFS_MAGIC && 4189 (sb->fs_version > MTB_UFS_VERSION_1 || 4190 sb->fs_version < MTB_UFS_VERSION_MIN)) { 4191 cur_cgrp = 0; 4192 if (!override) { 4193 printf("invalid super block "); 4194 printf("magic word\n"); 4195 cur_cgrp--; 4196 error++; 4197 return; 4198 } 4199 } 4200 if (cur_cgrp == 0) 4201 printf("\tsuper block:\n"); 4202 else { 4203 printf("\tsuper block in cylinder "); 4204 printf("group "); 4205 print(cur_cgrp - 1, 0, 0, 0); 4206 printf(":\n"); 4207 } 4208 printsb(sb); 4209 if (tcount) 4210 printf("\n"); 4211 } 4212 cur_cgrp--; 4213 if (end) { 4214 printf("end of super blocks\n"); 4215 error++; 4216 } 4217 return; 4218 4219 case 'S': /* print as shadow data */ 4220 if (type == NUMB) { 4221 type = FRAGMENT; 4222 cur_shad = 0; 4223 cur_bytes = fragoff(fs, addr); 4224 bod_addr = addr - cur_bytes; 4225 /* no more than two fragments */ 4226 filesize = fragroundup(fs, 4227 bod_addr + FRGSIZE + 1); 4228 } 4229 objsz = SHADOW_DATA; 4230 while (tcount-- && 4231 (cur_bytes + SHADOW_DATA) <= filesize && 4232 (type != SHADOW_DATA || 4233 (cur_bytes + SHADOW_DATA)) <= blocksize) { 4234 /*LINTED*/ 4235 struct ufs_fsd fsd; 4236 long tcur_bytes; 4237 4238 taddr = addr; 4239 tcur_bytes = cur_bytes; 4240 index(base); 4241 getshadowdata((long *)&fsd, LONG + LONG); 4242 printf(" type: "); 4243 print((long)fsd.fsd_type, 8, -8, 0); 4244 printf(" size: "); 4245 print((long)fsd.fsd_size, 8, -8, 0); 4246 tbase = fsd.fsd_size - LONG - LONG; 4247 if (tbase > 256) 4248 tbase = 256; 4249 for (i = 0; i < tbase; i++) { 4250 if (i % LONG == 0) { 4251 if (i % 16 == 0) { 4252 printf("\n"); 4253 index(base); 4254 } else 4255 printf(" "); 4256 getshadowdata(&temp, LONG); 4257 p = (char *)&temp; 4258 } else 4259 printf(" "); 4260 printf("%02x", (int)(*p++ & 0377L)); 4261 } 4262 printf("\n"); 4263 addr = taddr; 4264 cur_bytes = tcur_bytes; 4265 erraddr = addr; 4266 errcur_bytes = cur_bytes; 4267 addr += FSD_RECSZ((&fsd), fsd.fsd_size); 4268 cur_bytes += FSD_RECSZ((&fsd), fsd.fsd_size); 4269 cur_shad++; 4270 syncshadowscan(0); 4271 } 4272 addr = erraddr; 4273 cur_bytes = errcur_bytes; 4274 cur_shad--; 4275 if (tcount >= 0 && !star) { 4276 switch (type) { 4277 case FRAGMENT: 4278 printf("end of fragment\n"); 4279 break; 4280 default: 4281 printf("end of shadow data\n"); 4282 } 4283 error++; 4284 } else 4285 error = 0; 4286 return; 4287 default: 4288 error++; 4289 printf("no such print option\n"); 4290 return; 4291 } 4292 } 4293 4294 /* 4295 * valid_addr - call check_addr to validate the current address. 4296 */ 4297 static int 4298 valid_addr() 4299 { 4300 short end = 0, eof = 0; 4301 long tcount = count; 4302 4303 if (!trapped) 4304 return (1); 4305 if (cur_bytes < 0) { 4306 cur_bytes = 0; 4307 if (blocksize > filesize) { 4308 printf("beginning of file\n"); 4309 } else { 4310 if (type == BLOCK) 4311 printf("beginning of block\n"); 4312 else 4313 printf("beginning of fragment\n"); 4314 } 4315 error++; 4316 return (0); 4317 } 4318 count = 1; 4319 (void) check_addr(1, &end, &eof, (filesize < blocksize)); 4320 count = tcount; 4321 if (eof) { 4322 printf("end of file\n"); 4323 error++; 4324 return (0); 4325 } 4326 if (end == 2) { 4327 if (erraddr > addr) { 4328 if (type == BLOCK) 4329 printf("beginning of block\n"); 4330 else 4331 printf("beginning of fragment\n"); 4332 error++; 4333 return (0); 4334 } 4335 } 4336 if (end) { 4337 if (type == BLOCK) 4338 printf("end of block\n"); 4339 else 4340 printf("end of fragment\n"); 4341 error++; 4342 return (0); 4343 } 4344 return (1); 4345 } 4346 4347 /* 4348 * check_addr - check if the address crosses the end of block or 4349 * end of file. Return the proper count. 4350 */ 4351 static int 4352 check_addr(eof_flag, end, eof, keep_on) 4353 short eof_flag, *end, *eof, keep_on; 4354 { 4355 long temp, tcount = count, tcur_bytes = cur_bytes; 4356 u_offset_t taddr = addr; 4357 4358 if (bcomp(addr + count * objsz - 1) || 4359 (keep_on && taddr < (bmap(cur_block) << FRGSHIFT))) { 4360 error = 0; 4361 addr = taddr; 4362 cur_bytes = tcur_bytes; 4363 if (keep_on) { 4364 if (addr < erraddr) { 4365 if (cur_bytes < 0) { 4366 (*end) = 2; 4367 return (0); /* Value ignored */ 4368 } 4369 temp = cur_block - lblkno(fs, cur_bytes); 4370 cur_block -= temp; 4371 if ((addr = bmap(cur_block) << FRGSHIFT) == 0) { 4372 cur_block += temp; 4373 return (0); /* Value ignored */ 4374 } 4375 temp = tcur_bytes - cur_bytes; 4376 addr += temp; 4377 cur_bytes += temp; 4378 return (0); /* Value ignored */ 4379 } else { 4380 if (cur_bytes >= filesize) { 4381 (*eof)++; 4382 return (0); /* Value ignored */ 4383 } 4384 temp = lblkno(fs, cur_bytes) - cur_block; 4385 cur_block += temp; 4386 if ((addr = bmap(cur_block) << FRGSHIFT) == 0) { 4387 cur_block -= temp; 4388 return (0); /* Value ignored */ 4389 } 4390 temp = tcur_bytes - cur_bytes; 4391 addr += temp; 4392 cur_bytes += temp; 4393 return (0); /* Value ignored */ 4394 } 4395 } 4396 tcount = (blkroundup(fs, addr+1)-addr) / objsz; 4397 if (!star) 4398 (*end) = 2; 4399 } 4400 addr = taddr; 4401 cur_bytes = tcur_bytes; 4402 if (eof_flag) { 4403 if (blocksize > filesize) { 4404 if (cur_bytes >= filesize) { 4405 tcount = 0; 4406 (*eof)++; 4407 } else if (tcount > (filesize - cur_bytes) / objsz) { 4408 tcount = (filesize - cur_bytes) / objsz; 4409 if (!star || tcount == 0) 4410 (*eof)++; 4411 } 4412 } else { 4413 if (cur_bytes >= blocksize) { 4414 tcount = 0; 4415 (*end)++; 4416 } else if (tcount > (blocksize - cur_bytes) / objsz) { 4417 tcount = (blocksize - cur_bytes) / objsz; 4418 if (!star || tcount == 0) 4419 (*end)++; 4420 } 4421 } 4422 } 4423 return (tcount); 4424 } 4425 4426 /* 4427 * print_check - check if the index needs to be printed and delete 4428 * rows of zeros from the output. 4429 */ 4430 unsigned long * 4431 print_check(lptr, tcount, tbase, i) 4432 unsigned long *lptr; 4433 long *tcount; 4434 short tbase; 4435 register int i; 4436 { 4437 register int j, k, temp = BYTESPERLINE / objsz; 4438 short first_time = 0; 4439 unsigned long *tlptr; 4440 unsigned short *tsptr, *sptr; 4441 4442 sptr = (unsigned short *)lptr; 4443 if (i == 0) 4444 first_time = 1; 4445 if (i % temp == 0) { 4446 if (*tcount >= temp - 1) { 4447 if (objsz == SHORT) 4448 tsptr = sptr; 4449 else 4450 tlptr = lptr; 4451 k = *tcount - 1; 4452 for (j = i; k--; j++) 4453 if (objsz == SHORT) { 4454 if (*tsptr++ != 0) 4455 break; 4456 } else { 4457 if (*tlptr++ != 0) 4458 break; 4459 } 4460 if (j > (i + temp - 1)) { 4461 j = (j - i) / temp; 4462 while (j-- > 0) { 4463 if (objsz == SHORT) 4464 sptr += temp; 4465 else 4466 lptr += temp; 4467 *tcount -= temp; 4468 i += temp; 4469 addr += BYTESPERLINE; 4470 cur_bytes += BYTESPERLINE; 4471 } 4472 if (first_time) 4473 printf("*"); 4474 else 4475 printf("\n*"); 4476 } 4477 if (i) 4478 printf("\n"); 4479 index(tbase); 4480 } else { 4481 if (i) 4482 printf("\n"); 4483 index(tbase); 4484 } 4485 } 4486 if (objsz == SHORT) 4487 /*LINTED*/ 4488 return ((unsigned long *)sptr); 4489 else 4490 return (lptr); 4491 } 4492 4493 /* 4494 * index - print a byte index for the printout in base b 4495 * with leading zeros. 4496 */ 4497 static void 4498 index(b) 4499 int b; 4500 { 4501 int tbase = base; 4502 4503 base = b; 4504 print(addr, 8, 8, 1); 4505 printf(":\t"); 4506 base = tbase; 4507 } 4508 4509 /* 4510 * print - print out the value to digits places with/without 4511 * leading zeros and right/left justified in the current base. 4512 */ 4513 static void 4514 #ifdef _LARGEFILE64_SOURCE 4515 printll(u_offset_t value, int fieldsz, int digits, int lead) 4516 #else /* !_LARGEFILE64_SOURCE */ 4517 print(long value, int fieldsz, int digits, int lead) 4518 #endif /* _LARGEFILE64_SOURCE */ 4519 { 4520 register int i, left = 0; 4521 char mode = BASE[base - OCTAL]; 4522 char *string = &scratch[0]; 4523 4524 if (digits < 0) { 4525 left = 1; 4526 digits *= -1; 4527 } 4528 if (base != HEX) 4529 if (digits) 4530 digits = digits + (digits - 1)/((base >> 1) - 1) + 1; 4531 else 4532 digits = 1; 4533 if (lead) { 4534 if (left) 4535 (void) sprintf(string, "%%%c%d%d.%d" 4536 #ifdef _LARGEFILE64_SOURCE 4537 "ll" 4538 #endif /* _LARGEFILE64_SOURCE */ 4539 "%c", '-', 0, digits, lead, mode); 4540 else 4541 (void) sprintf(string, "%%%d%d.%d" 4542 #ifdef _LARGEFILE64_SOURCE 4543 "ll" 4544 #endif /* _LARGEFILE64_SOURCE */ 4545 "%c", 0, digits, lead, mode); 4546 } else { 4547 if (left) 4548 (void) sprintf(string, "%%%c%d" 4549 #ifdef _LARGEFILE64_SOURCE 4550 "ll" 4551 #endif /* _LARGEFILE64_SOURCE */ 4552 "%c", '-', digits, mode); 4553 else 4554 (void) sprintf(string, "%%%d" 4555 #ifdef _LARGEFILE64_SOURCE 4556 "ll" 4557 #endif /* _LARGEFILE64_SOURCE */ 4558 "%c", digits, mode); 4559 } 4560 printf(string, value); 4561 for (i = 0; i < fieldsz - digits; i++) 4562 printf(" "); 4563 } 4564 4565 /* 4566 * Print out the contents of a superblock. 4567 */ 4568 static void 4569 printsb(fs) 4570 struct fs *fs; 4571 { 4572 int c, i, j, k, size; 4573 caddr_t sip; 4574 time_t t; 4575 4576 t = fs->fs_time; 4577 #ifdef FS_42POSTBLFMT 4578 if (fs->fs_postblformat == FS_42POSTBLFMT) 4579 fs->fs_nrpos = 8; 4580 printf("magic\t%lx\tformat\t%s\ttime\t%s", fs->fs_magic, 4581 fs->fs_postblformat == FS_42POSTBLFMT ? "static" : "dynamic", 4582 ctime(&t)); 4583 #else 4584 printf("magic\t%x\ttime\t%s", 4585 fs->fs_magic, ctime(&t)); 4586 #endif 4587 if (fs->fs_magic == MTB_UFS_MAGIC) 4588 printf("version\t%x\n", fs->fs_version); 4589 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n", 4590 fs->fs_cstotal.cs_nbfree, fs->fs_cstotal.cs_ndir, 4591 fs->fs_cstotal.cs_nifree, fs->fs_cstotal.cs_nffree); 4592 printf("ncg\t%ld\tncyl\t%ld\tsize\t%ld\tblocks\t%ld\n", 4593 fs->fs_ncg, fs->fs_ncyl, fs->fs_size, fs->fs_dsize); 4594 printf("bsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n", 4595 fs->fs_bsize, fs->fs_bshift, fs->fs_bmask); 4596 printf("fsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n", 4597 fs->fs_fsize, fs->fs_fshift, fs->fs_fmask); 4598 printf("frag\t%ld\tshift\t%ld\tfsbtodb\t%ld\n", 4599 fs->fs_frag, fs->fs_fragshift, fs->fs_fsbtodb); 4600 printf("cpg\t%ld\tbpg\t%ld\tfpg\t%ld\tipg\t%ld\n", 4601 fs->fs_cpg, fs->fs_fpg / fs->fs_frag, fs->fs_fpg, fs->fs_ipg); 4602 printf("minfree\t%ld%%\toptim\t%s\tmaxcontig %ld\tmaxbpg\t%ld\n", 4603 fs->fs_minfree, fs->fs_optim == FS_OPTSPACE ? "space" : "time", 4604 fs->fs_maxcontig, fs->fs_maxbpg); 4605 #ifdef FS_42POSTBLFMT 4606 #ifdef sun 4607 printf("rotdelay %ldms\tfs_id[0] 0x%lx\tfs_id[1] 0x%lx\trps\t%ld\n", 4608 fs->fs_rotdelay, fs->fs_id[0], fs->fs_id[1], fs->fs_rps); 4609 #else 4610 printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n", 4611 fs->fs_rotdelay, fs->fs_headswitch, fs->fs_trkseek, fs->fs_rps); 4612 #endif /* sun */ 4613 printf("ntrak\t%ld\tnsect\t%ld\tnpsect\t%ld\tspc\t%ld\n", 4614 fs->fs_ntrak, fs->fs_nsect, fs->fs_npsect, fs->fs_spc); 4615 printf("trackskew %ld\n", fs->fs_trackskew); 4616 #else 4617 printf("rotdelay %ldms\trps\t%ld\n", 4618 fs->fs_rotdelay, fs->fs_rps); 4619 printf("ntrak\t%ld\tnsect\t%ld\tspc\t%ld\n", 4620 fs->fs_ntrak, fs->fs_nsect, fs->fs_spc); 4621 #endif 4622 printf("si %ld\n", fs->fs_si); 4623 printf("nindir\t%ld\tinopb\t%ld\tnspf\t%ld\n", 4624 fs->fs_nindir, fs->fs_inopb, fs->fs_nspf); 4625 printf("sblkno\t%ld\tcblkno\t%ld\tiblkno\t%ld\tdblkno\t%ld\n", 4626 fs->fs_sblkno, fs->fs_cblkno, fs->fs_iblkno, fs->fs_dblkno); 4627 printf("sbsize\t%ld\tcgsize\t%ld\tcgoffset %ld\tcgmask\t0x%08lx\n", 4628 fs->fs_sbsize, fs->fs_cgsize, fs->fs_cgoffset, fs->fs_cgmask); 4629 printf("csaddr\t%ld\tcssize\t%ld\tshift\t%ld\tmask\t0x%08lx\n", 4630 fs->fs_csaddr, fs->fs_cssize, fs->fs_csshift, fs->fs_csmask); 4631 printf("cgrotor\t%ld\tfmod\t%d\tronly\t%d\n", 4632 fs->fs_cgrotor, fs->fs_fmod, fs->fs_ronly); 4633 #ifdef FS_42POSTBLFMT 4634 if (fs->fs_cpc != 0) 4635 printf("blocks available in each of %ld rotational positions", 4636 fs->fs_nrpos); 4637 else 4638 printf("insufficient space to maintain rotational tables\n"); 4639 #endif 4640 for (c = 0; c < fs->fs_cpc; c++) { 4641 printf("\ncylinder number %d:", c); 4642 #ifdef FS_42POSTBLFMT 4643 for (i = 0; i < fs->fs_nrpos; i++) { 4644 /*LINTED*/ 4645 if (fs_postbl(fs, c)[i] == -1) 4646 continue; 4647 printf("\n position %d:\t", i); 4648 /*LINTED*/ 4649 for (j = fs_postbl(fs, c)[i], k = 1; /* void */; 4650 j += fs_rotbl(fs)[j], k++) { 4651 printf("%5d", j); 4652 if (k % 12 == 0) 4653 printf("\n\t\t"); 4654 if (fs_rotbl(fs)[j] == 0) 4655 break; 4656 } 4657 } 4658 #else 4659 for (i = 0; i < NRPOS; i++) { 4660 if (fs->fs_postbl[c][i] == -1) 4661 continue; 4662 printf("\n position %d:\t", i); 4663 for (j = fs->fs_postbl[c][i], k = 1; /* void */; 4664 j += fs->fs_rotbl[j], k++) { 4665 printf("%5d", j); 4666 if (k % 12 == 0) 4667 printf("\n\t\t"); 4668 if (fs->fs_rotbl[j] == 0) 4669 break; 4670 } 4671 } 4672 #endif 4673 } 4674 printf("\ncs[].cs_(nbfree, ndir, nifree, nffree):"); 4675 sip = calloc(1, fs->fs_cssize); 4676 fs->fs_u.fs_csp = (struct csum *)sip; 4677 for (i = 0, j = 0; i < fs->fs_cssize; i += fs->fs_bsize, j++) { 4678 size = fs->fs_cssize - i < fs->fs_bsize ? 4679 fs->fs_cssize - i : fs->fs_bsize; 4680 (void) llseek(fd, 4681 (offset_t)fsbtodb(fs, (fs->fs_csaddr + j * fs->fs_frag)) 4682 * fs->fs_fsize / fsbtodb(fs, 1), 0); 4683 if (read(fd, sip, size) != size) { 4684 free(fs->fs_u.fs_csp); 4685 return; 4686 } 4687 sip += size; 4688 } 4689 for (i = 0; i < fs->fs_ncg; i++) { 4690 struct csum *cs = &fs->fs_cs(fs, i); 4691 if (i % 4 == 0) 4692 printf("\n "); 4693 printf("%d:(%ld,%ld,%ld,%ld) ", i, cs->cs_nbfree, cs->cs_ndir, 4694 cs->cs_nifree, cs->cs_nffree); 4695 } 4696 free(fs->fs_u.fs_csp); 4697 printf("\n"); 4698 if (fs->fs_ncyl % fs->fs_cpg) { 4699 printf("cylinders in last group %d\n", 4700 i = fs->fs_ncyl % fs->fs_cpg); 4701 printf("blocks in last group %ld\n", 4702 i * fs->fs_spc / NSPB(fs)); 4703 } 4704 } 4705 4706 /* 4707 * Print out the contents of a cylinder group. 4708 */ 4709 static void 4710 printcg(cg) 4711 struct cg *cg; 4712 { 4713 int i, j; 4714 time_t t; 4715 4716 printf("\ncg %ld:\n", cg->cg_cgx); 4717 t = cg->cg_time; 4718 #ifdef FS_42POSTBLFMT 4719 printf("magic\t%lx\ttell\t%llx\ttime\t%s", 4720 fs->fs_postblformat == FS_42POSTBLFMT ? 4721 ((struct ocg *)cg)->cg_magic : cg->cg_magic, 4722 fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1), 4723 ctime(&t)); 4724 #else 4725 printf("magic\t%x\ttell\t%llx\ttime\t%s", 4726 cg->cg_magic, 4727 fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1), 4728 ctime(&t)); 4729 #endif 4730 printf("cgx\t%ld\tncyl\t%d\tniblk\t%d\tndblk\t%ld\n", 4731 cg->cg_cgx, cg->cg_ncyl, cg->cg_niblk, cg->cg_ndblk); 4732 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n", 4733 cg->cg_cs.cs_nbfree, cg->cg_cs.cs_ndir, 4734 cg->cg_cs.cs_nifree, cg->cg_cs.cs_nffree); 4735 printf("rotor\t%ld\tirotor\t%ld\tfrotor\t%ld\nfrsum", 4736 cg->cg_rotor, cg->cg_irotor, cg->cg_frotor); 4737 for (i = 1, j = 0; i < fs->fs_frag; i++) { 4738 printf("\t%ld", cg->cg_frsum[i]); 4739 j += i * cg->cg_frsum[i]; 4740 } 4741 printf("\nsum of frsum: %d\niused:\t", j); 4742 pbits((unsigned char *)cg_inosused(cg), fs->fs_ipg); 4743 printf("free:\t"); 4744 pbits(cg_blksfree(cg), fs->fs_fpg); 4745 printf("b:\n"); 4746 for (i = 0; i < fs->fs_cpg; i++) { 4747 /*LINTED*/ 4748 if (cg_blktot(cg)[i] == 0) 4749 continue; 4750 /*LINTED*/ 4751 printf(" c%d:\t(%ld)\t", i, cg_blktot(cg)[i]); 4752 #ifdef FS_42POSTBLFMT 4753 for (j = 0; j < fs->fs_nrpos; j++) { 4754 if (fs->fs_cpc == 0 || 4755 /*LINTED*/ 4756 fs_postbl(fs, i % fs->fs_cpc)[j] == -1) 4757 continue; 4758 /*LINTED*/ 4759 printf(" %d", cg_blks(fs, cg, i)[j]); 4760 } 4761 #else 4762 for (j = 0; j < NRPOS; j++) { 4763 if (fs->fs_cpc == 0 || 4764 fs->fs_postbl[i % fs->fs_cpc][j] == -1) 4765 continue; 4766 printf(" %d", cg->cg_b[i][j]); 4767 } 4768 #endif 4769 printf("\n"); 4770 } 4771 } 4772 4773 /* 4774 * Print out the contents of a bit array. 4775 */ 4776 static void 4777 pbits(cp, max) 4778 register unsigned char *cp; 4779 int max; 4780 { 4781 register int i; 4782 int count = 0, j; 4783 4784 for (i = 0; i < max; i++) 4785 if (isset(cp, i)) { 4786 if (count) 4787 printf(",%s", count % 6 ? " " : "\n\t"); 4788 count++; 4789 printf("%d", i); 4790 j = i; 4791 while ((i+1) < max && isset(cp, i+1)) 4792 i++; 4793 if (i != j) 4794 printf("-%d", i); 4795 } 4796 printf("\n"); 4797 } 4798 4799 /* 4800 * bcomp - used to check for block over/under flows when stepping through 4801 * a file system. 4802 */ 4803 static int 4804 bcomp(addr) 4805 u_offset_t addr; 4806 { 4807 if (override) 4808 return (0); 4809 4810 if (lblkno(fs, addr) == (bhdr.fwd)->blkno) 4811 return (0); 4812 error++; 4813 return (1); 4814 } 4815 4816 /* 4817 * bmap - maps the logical block number of a file into 4818 * the corresponding physical block on the file 4819 * system. 4820 */ 4821 static long 4822 bmap(bn) 4823 long bn; 4824 { 4825 register int j; 4826 register struct dinode *ip; 4827 int sh; 4828 long nb; 4829 register char *cptr; 4830 4831 if ((cptr = getblk(cur_ino)) == 0) 4832 return (0); 4833 4834 cptr += blkoff(fs, cur_ino); 4835 4836 /*LINTED*/ 4837 ip = (struct dinode *)cptr; 4838 4839 if (bn < NDADDR) { 4840 nb = ip->di_db[bn]; 4841 return (nullblk(nb) ? 0L : nb); 4842 } 4843 4844 sh = 1; 4845 bn -= NDADDR; 4846 for (j = NIADDR; j > 0; j--) { 4847 sh *= NINDIR(fs); 4848 if (bn < sh) 4849 break; 4850 bn -= sh; 4851 } 4852 if (j == 0) { 4853 printf("file too big\n"); 4854 error++; 4855 return (0L); 4856 } 4857 addr = (uintptr_t)&ip->di_ib[NIADDR - j]; 4858 nb = get(LONG); 4859 if (nb == 0) 4860 return (0L); 4861 for (; j <= NIADDR; j++) { 4862 sh /= NINDIR(fs); 4863 addr = (nb << FRGSHIFT) + ((bn / sh) % NINDIR(fs)) * LONG; 4864 if (nullblk(nb = get(LONG))) 4865 return (0L); 4866 } 4867 return (nb); 4868 } 4869 4870 #if defined(OLD_FSDB_COMPATIBILITY) 4871 4872 /* 4873 * The following are "tacked on" to support the old fsdb functionality 4874 * of clearing an inode. (All together now...) "It's better to use clri". 4875 */ 4876 4877 #define ISIZE (sizeof (struct dinode)) 4878 #define NI (MAXBSIZE/ISIZE) 4879 4880 4881 static struct dinode di_buf[NI]; 4882 4883 static union { 4884 char dummy[SBSIZE]; 4885 struct fs sblk; 4886 } sb_un; 4887 4888 #define sblock sb_un.sblk 4889 4890 static void 4891 old_fsdb(inum, special) 4892 int inum; 4893 char *special; 4894 { 4895 int f; /* File descriptor for "special" */ 4896 int j; 4897 int status = 0; 4898 u_offset_t off; 4899 long gen; 4900 time_t t; 4901 4902 f = open(special, 2); 4903 if (f < 0) { 4904 perror("open"); 4905 printf("cannot open %s\n", special); 4906 exit(31+4); 4907 } 4908 (void) llseek(f, (offset_t)SBLOCK * DEV_BSIZE, 0); 4909 if (read(f, &sblock, SBSIZE) != SBSIZE) { 4910 printf("cannot read %s\n", special); 4911 exit(31+4); 4912 } 4913 if (sblock.fs_magic != FS_MAGIC) { 4914 printf("bad super block magic number\n"); 4915 exit(31+4); 4916 } 4917 if (inum == 0) { 4918 printf("%d: is zero\n", inum); 4919 exit(31+1); 4920 } 4921 off = (u_offset_t)fsbtodb(&sblock, itod(&sblock, inum)) * DEV_BSIZE; 4922 (void) llseek(f, off, 0); 4923 if (read(f, (char *)di_buf, sblock.fs_bsize) != sblock.fs_bsize) { 4924 printf("%s: read error\n", special); 4925 status = 1; 4926 } 4927 if (status) 4928 exit(31+status); 4929 4930 /* 4931 * Update the time in superblock, so fsck will check this filesystem. 4932 */ 4933 (void) llseek(f, (offset_t)(SBLOCK * DEV_BSIZE), 0); 4934 (void) time(&t); 4935 sblock.fs_time = (time32_t)t; 4936 if (write(f, &sblock, SBSIZE) != SBSIZE) { 4937 printf("cannot update %s\n", special); 4938 exit(35); 4939 } 4940 4941 printf("clearing %u\n", inum); 4942 off = (u_offset_t)fsbtodb(&sblock, itod(&sblock, inum)) * DEV_BSIZE; 4943 (void) llseek(f, off, 0); 4944 read(f, (char *)di_buf, sblock.fs_bsize); 4945 j = itoo(&sblock, inum); 4946 gen = di_buf[j].di_gen; 4947 (void) memset((caddr_t)&di_buf[j], 0, ISIZE); 4948 di_buf[j].di_gen = gen + 1; 4949 (void) llseek(f, off, 0); 4950 write(f, (char *)di_buf, sblock.fs_bsize); 4951 exit(31+status); 4952 } 4953 4954 static int 4955 isnumber(s) 4956 char *s; 4957 { 4958 register int c; 4959 4960 if (s == NULL) 4961 return (0); 4962 while ((c = *s++) != NULL) 4963 if (c < '0' || c > '9') 4964 return (0); 4965 return (1); 4966 } 4967 #endif /* OLD_FSDB_COMPATIBILITY */ 4968 4969 enum boolean { True, False }; 4970 extent_block_t *log_eb; 4971 ml_odunit_t *log_odi; 4972 int lufs_tid; /* last valid TID seen */ 4973 4974 /* 4975 * no single value is safe to use to indicate 4976 * lufs_tid being invalid so we need a 4977 * seperate variable. 4978 */ 4979 enum boolean lufs_tid_valid; 4980 4981 /* 4982 * log_get_header_info - get the basic info of the logging filesystem 4983 */ 4984 int 4985 log_get_header_info(void) 4986 { 4987 char *b; 4988 int nb; 4989 4990 /* 4991 * Mark the global tid as invalid everytime we're called to 4992 * prevent any false positive responses. 4993 */ 4994 lufs_tid_valid = False; 4995 4996 /* 4997 * See if we've already set up the header areas. The only problem 4998 * with this approach is we don't reread the on disk data though 4999 * it shouldn't matter since we don't operate on a live disk. 5000 */ 5001 if ((log_eb != NULL) && (log_odi != NULL)) 5002 return (1); 5003 5004 /* 5005 * Either logging is disabled or we've not running 2.7. 5006 */ 5007 if (fs->fs_logbno == 0) { 5008 printf("Logging doesn't appear to be enabled on this disk\n"); 5009 return (0); 5010 } 5011 5012 /* 5013 * To find the log we need to first pick up the block allocation 5014 * data. The block number for that data is fs_logbno in the 5015 * super block. 5016 */ 5017 if ((b = getblk((u_offset_t)ldbtob(logbtodb(fs, fs->fs_logbno)))) 5018 == 0) { 5019 printf("getblk() indicates an error with logging block\n"); 5020 return (0); 5021 } 5022 5023 /* 5024 * Next we need to figure out how big the extent data structure 5025 * really is. It can't be more then fs_bsize and you could just 5026 * allocate that but, why get sloppy. 5027 * 1 is subtracted from nextents because extent_block_t contains 5028 * a single extent_t itself. 5029 */ 5030 log_eb = (extent_block_t *)b; 5031 if (log_eb->type != LUFS_EXTENTS) { 5032 printf("Extents block has invalid type (0x%x)\n", 5033 log_eb->type); 5034 return (0); 5035 } 5036 nb = sizeof (extent_block_t) + 5037 (sizeof (extent_t) * (log_eb->nextents - 1)); 5038 5039 log_eb = (extent_block_t *)malloc(nb); 5040 if (log_eb == NULL) { 5041 printf("Failed to allocate memory for extent block log\n"); 5042 return (0); 5043 } 5044 memcpy(log_eb, b, nb); 5045 5046 if (log_eb->nextbno != 0) 5047 /* 5048 * Currently, as of 11-Dec-1997 the field nextbno isn't 5049 * implemented. If someone starts using this sucker we'd 5050 * better warn somebody. 5051 */ 5052 printf("WARNING: extent block field nextbno is non-zero!\n"); 5053 5054 /* 5055 * Now read in the on disk log structure. This is always in the 5056 * first block of the first extent. 5057 */ 5058 b = getblk((u_offset_t)ldbtob(logbtodb(fs, log_eb->extents[0].pbno))); 5059 log_odi = (ml_odunit_t *)malloc(sizeof (ml_odunit_t)); 5060 if (log_odi == NULL) { 5061 free(log_eb); 5062 log_eb = NULL; 5063 printf("Failed to allocate memory for ondisk structure\n"); 5064 return (0); 5065 } 5066 memcpy(log_odi, b, sizeof (ml_odunit_t)); 5067 5068 /* 5069 * Consistency checks. 5070 */ 5071 if (log_odi->od_version != LUFS_VERSION_LATEST) { 5072 free(log_eb); 5073 log_eb = NULL; 5074 free(log_odi); 5075 log_odi = NULL; 5076 printf("Version mismatch in on-disk version of log data\n"); 5077 return (0); 5078 } else if (log_odi->od_badlog) { 5079 printf("WARNING: Log was marked as bad\n"); 5080 } 5081 5082 return (1); 5083 } 5084 5085 log_display_header(void) 5086 { 5087 int x; 5088 if (!log_get_header_info()) 5089 /* 5090 * No need to display anything here. The previous routine 5091 * has already done so. 5092 */ 5093 return; 5094 5095 if (fs->fs_magic == FS_MAGIC) 5096 printf("Log block number: 0x%x\n------------------\n", 5097 fs->fs_logbno); 5098 else 5099 printf("Log frag number: 0x%x\n------------------\n", 5100 fs->fs_logbno); 5101 printf("Extent Info\n\t# Extents : %d\n\t# Bytes : 0x%x\n", 5102 log_eb->nextents, log_eb->nbytes); 5103 printf("\tNext Block : 0x%x\n\tExtent List\n\t--------\n", 5104 log_eb->nextbno); 5105 for (x = 0; x < log_eb->nextents; x++) 5106 printf("\t [%d] lbno 0x%08x pbno 0x%08x nbno 0x%08x\n", 5107 x, log_eb->extents[x].lbno, log_eb->extents[x].pbno, 5108 log_eb->extents[x].nbno); 5109 for (x = 0; x < log_eb->nextents; x++) 5110 printf("\t [%d] lbno 0x%08x pbno 0x%08x nbno 0x%08x\n", 5111 x, log_eb->extents[x].lbno, log_eb->extents[x].pbno, 5112 log_eb->extents[x].nbno); 5113 printf("\nOn Disk Info\n\tbol_lof : 0x%08x\n\teol_lof : 0x%08x\n", 5114 log_odi->od_bol_lof, log_odi->od_eol_lof); 5115 printf("\tlog_size : 0x%08x\n", 5116 log_odi->od_logsize); 5117 printf("\thead_lof : 0x%08x\tident : 0x%x\n", 5118 log_odi->od_head_lof, log_odi->od_head_ident); 5119 printf("\ttail_lof : 0x%08x\tident : 0x%x\n\thead_tid : 0x%08x\n", 5120 log_odi->od_tail_lof, log_odi->od_tail_ident, log_odi->od_head_tid); 5121 printf("\tcheck sum : 0x%08x\n", log_odi->od_chksum); 5122 if (log_odi->od_chksum != 5123 (log_odi->od_head_ident + log_odi->od_tail_ident)) 5124 printf("bad checksum: found 0x%08x, should be 0x%08x\n", 5125 log_odi->od_chksum, 5126 log_odi->od_head_ident + log_odi->od_tail_ident); 5127 if (log_odi->od_head_lof == log_odi->od_tail_lof) 5128 printf("\t --- Log is empty ---\n"); 5129 } 5130 5131 /* 5132 * log_lodb -- logical log offset to disk block number 5133 */ 5134 log_lodb(u_offset_t off, diskaddr_t *pblk) 5135 { 5136 uint32_t lblk = (uint32_t)btodb(off); 5137 int x; 5138 5139 for (x = 0; x < log_eb->nextents; x++) 5140 if ((lblk >= log_eb->extents[x].lbno) && 5141 (lblk < (log_eb->extents[x].lbno + 5142 log_eb->extents[x].nbno))) { 5143 *pblk = (diskaddr_t)lblk - log_eb->extents[x].lbno + 5144 logbtodb(fs, log_eb->extents[x].pbno); 5145 return (1); 5146 } 5147 return (0); 5148 } 5149 5150 /* 5151 * String names for the enumerated types. These are only used 5152 * for display purposes. 5153 */ 5154 char *dt_str[] = { 5155 "DT_NONE", "DT_SB", "DT_CG", "DT_SI", "DT_AB", 5156 "DT_ABZERO", "DT_DIR", "DT_INODE", "DT_FBI", 5157 "DT_QR", "DT_COMMIT", "DT_CANCEL", "DT_BOT", 5158 "DT_EOT", "DT_UD", "DT_SUD", "DT_SHAD", "DT_MAX" 5159 }; 5160 5161 /* 5162 * log_read_log -- transfer information from the log and adjust offset 5163 */ 5164 log_read_log(u_offset_t *addr, caddr_t va, int nb, uint32_t *chk) 5165 { 5166 int xfer; 5167 caddr_t bp; 5168 diskaddr_t pblk; 5169 sect_trailer_t *st; 5170 5171 while (nb) { 5172 if (!log_lodb(*addr, &pblk)) { 5173 printf("Invalid log offset\n"); 5174 return (0); 5175 } 5176 5177 /* 5178 * fsdb getblk() expects offsets not block number. 5179 */ 5180 if ((bp = getblk((u_offset_t)dbtob(pblk))) == NULL) 5181 return (0); 5182 5183 xfer = MIN(NB_LEFT_IN_SECTOR(*addr), nb); 5184 if (va != NULL) { 5185 memcpy(va, bp + blkoff(fs, *addr), xfer); 5186 va += xfer; 5187 } 5188 nb -= xfer; 5189 *addr += xfer; 5190 5191 /* 5192 * If the log offset is now at a sector trailer 5193 * run the checks if requested. 5194 */ 5195 if (NB_LEFT_IN_SECTOR(*addr) == 0) { 5196 if (chk != NULL) { 5197 st = (sect_trailer_t *) 5198 (bp + blkoff(fs, *addr)); 5199 if (*chk != st->st_ident) { 5200 printf( 5201 "Expected sector trailer id 0x%08x, but saw 0x%08x\n", 5202 *chk, st->st_ident); 5203 return (0); 5204 } else { 5205 *chk = st->st_ident + 1; 5206 /* 5207 * We update the on disk structure 5208 * transaction ID each time we see 5209 * one. By comparing this value 5210 * to the last valid DT_COMMIT record 5211 * we can determine if our log is 5212 * completely valid. 5213 */ 5214 log_odi->od_head_tid = st->st_tid; 5215 } 5216 } 5217 *addr += sizeof (sect_trailer_t); 5218 } 5219 if ((int32_t)*addr == log_odi->od_eol_lof) 5220 *addr = log_odi->od_bol_lof; 5221 } 5222 return (1); 5223 } 5224 5225 u_offset_t 5226 log_nbcommit(u_offset_t a) 5227 { 5228 /* 5229 * Comments are straight from ufs_log.c 5230 * 5231 * log is the offset following the commit header. However, 5232 * if the commit header fell on the end-of-sector, then lof 5233 * has already been advanced to the beginning of the next 5234 * sector. So do nothgin. Otherwise, return the remaining 5235 * bytes in the sector. 5236 */ 5237 if ((a & (DEV_BSIZE - 1)) == 0) 5238 return (0); 5239 else 5240 return (NB_LEFT_IN_SECTOR(a)); 5241 } 5242 5243 /* 5244 * log_show -- pretty print the deltas. The number of which is determined 5245 * by the log_enum arg. If LOG_ALLDELTAS the routine, as the 5246 * name implies dumps everything. If LOG_NDELTAS, the routine 5247 * will print out "count" deltas starting at "addr". If 5248 * LOG_CHECKSCAN then run through the log checking the st_ident 5249 * for valid data. 5250 */ 5251 log_show(enum log_enum l) 5252 { 5253 struct delta d; 5254 int32_t bol, eol; 5255 int x = 0; 5256 uint32_t chk; 5257 5258 if (!log_get_header_info()) 5259 /* 5260 * No need to display any error messages here. The previous 5261 * routine has already done so. 5262 */ 5263 return; 5264 5265 bol = log_odi->od_head_lof; 5266 eol = log_odi->od_tail_lof; 5267 chk = log_odi->od_head_ident; 5268 5269 if (bol == eol) { 5270 if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) { 5271 printf("Empty log.\n"); 5272 return; 5273 } else 5274 printf("WARNING: empty log. addr may generate bogus" 5275 " information"); 5276 } 5277 5278 /* 5279 * Only reset the "addr" if we've been requested to show all 5280 * deltas in the log. 5281 */ 5282 if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) 5283 addr = (u_offset_t)bol; 5284 5285 if (l != LOG_CHECKSCAN) { 5286 printf(" Log Offset Delta Count Type\n"); 5287 printf("-----------------------------------------" 5288 "-----------------\n"); 5289 } 5290 5291 while ((bol != eol) && ((l == LOG_ALLDELTAS) || 5292 (l == LOG_CHECKSCAN) || count--)) { 5293 if (!log_read_log(&addr, (caddr_t)&d, sizeof (d), 5294 ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) ? 5295 &chk : NULL)) 5296 /* 5297 * Two failures are possible. One from getblk() 5298 * which prints out a message or when we've hit 5299 * an invalid block which may or may not indicate 5300 * an error 5301 */ 5302 goto end_scan; 5303 5304 if ((uint32_t)d.d_nb > log_odi->od_logsize) { 5305 printf("Bad delta entry. size out of bounds\n"); 5306 return; 5307 } 5308 if (l != LOG_CHECKSCAN) 5309 printf("[%04d] %08x %08x.%08x %08x %s\n", x++, bol, 5310 d.d_mof, d.d_nb, 5311 dt_str[d.d_typ >= DT_MAX ? DT_MAX : d.d_typ]); 5312 5313 switch (d.d_typ) { 5314 case DT_CANCEL: 5315 case DT_ABZERO: 5316 /* 5317 * These two deltas don't have log space 5318 * associated with the entry even though 5319 * d_nb is non-zero. 5320 */ 5321 break; 5322 5323 case DT_COMMIT: 5324 /* 5325 * Commit records have zero size yet, the 5326 * rest of the current disk block is avoided. 5327 */ 5328 addr += log_nbcommit(addr); 5329 lufs_tid = log_odi->od_head_tid; 5330 lufs_tid_valid = True; 5331 break; 5332 5333 default: 5334 if (!log_read_log(&addr, NULL, d.d_nb, 5335 ((l == LOG_ALLDELTAS) || 5336 (l == LOG_CHECKSCAN)) ? &chk : NULL)) 5337 goto end_scan; 5338 break; 5339 } 5340 bol = (int32_t)addr; 5341 } 5342 5343 end_scan: 5344 if (lufs_tid_valid == True) { 5345 if (lufs_tid == log_odi->od_head_tid) 5346 printf("scan -- okay\n"); 5347 else 5348 printf("scan -- some transactions have been lost\n"); 5349 } else { 5350 printf("scan -- failed to find a single valid transaction\n"); 5351 printf(" (possibly due to an empty log)\n"); 5352 } 5353 } 5354