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