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