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