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