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