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