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