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