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