Home | History | Annotate | Download | only in fsck
      1 /*
      2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
      7 /*	  All Rights Reserved  	*/
      8 
      9 /*
     10  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
     11  * All rights reserved.
     12  *
     13  * Redistribution and use in source and binary forms are permitted
     14  * provided that: (1) source distributions retain this entire copyright
     15  * notice and comment, and (2) distributions including binaries display
     16  * the following acknowledgement:  ``This product includes software
     17  * developed by the University of California, Berkeley and its contributors''
     18  * in the documentation or other materials provided with the distribution
     19  * and in all advertising materials mentioning features or use of this
     20  * software. Neither the name of the University nor the names of its
     21  * contributors may be used to endorse or promote products derived
     22  * from this software without specific prior written permission.
     23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     26  */
     27 
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <unistd.h>
     31 #include <stdarg.h>
     32 #include <libadm.h>
     33 #include <note.h>
     34 #include <sys/param.h>
     35 #include <sys/types.h>
     36 #include <sys/mntent.h>
     37 #include <sys/filio.h>
     38 #include <sys/fs/ufs_fs.h>
     39 #include <sys/vnode.h>
     40 #include <sys/fs/ufs_acl.h>
     41 #include <sys/fs/ufs_inode.h>
     42 #include <sys/fs/ufs_log.h>
     43 #define	_KERNEL
     44 #include <sys/fs/ufs_fsdir.h>
     45 #undef _KERNEL
     46 #include <sys/mnttab.h>
     47 #include <sys/types.h>
     48 #include <sys/stat.h>
     49 #include <fcntl.h>
     50 #include <signal.h>
     51 #include <string.h>
     52 #include <ctype.h>
     53 #include <sys/vfstab.h>
     54 #include <sys/lockfs.h>
     55 #include <errno.h>
     56 #include <sys/cmn_err.h>
     57 #include <sys/dkio.h>
     58 #include <sys/vtoc.h>
     59 #include <sys/efi_partition.h>
     60 #include <fslib.h>
     61 #include <inttypes.h>
     62 #include "fsck.h"
     63 
     64 caddr_t mount_point = NULL;
     65 
     66 static int64_t diskreads, totalreads;	/* Disk cache statistics */
     67 
     68 static int log_checksum(int32_t *, int32_t *, int);
     69 static void vdirerror(fsck_ino_t, caddr_t, va_list);
     70 static struct mnttab *search_mnttab(caddr_t, caddr_t, caddr_t, size_t);
     71 static struct vfstab *search_vfstab(caddr_t, caddr_t, caddr_t, size_t);
     72 static void vpwarn(caddr_t, va_list);
     73 static int getline(FILE *, caddr_t, int);
     74 static struct bufarea *alloc_bufarea(void);
     75 static void rwerror(caddr_t, diskaddr_t, int rval);
     76 static void debugclean(void);
     77 static void report_io_prob(caddr_t, diskaddr_t, size_t, ssize_t);
     78 static void freelogblk(daddr32_t);
     79 static void verrexit(caddr_t, va_list);
     80 static void vpfatal(caddr_t, va_list);
     81 static diskaddr_t get_device_size(int, caddr_t);
     82 static diskaddr_t brute_force_get_device_size(int);
     83 static void cg_constants(int, daddr32_t *, daddr32_t *, daddr32_t *,
     84 	    daddr32_t *, daddr32_t *, daddr32_t *);
     85 
     86 int
     87 ftypeok(struct dinode *dp)
     88 {
     89 	switch (dp->di_mode & IFMT) {
     90 
     91 	case IFDIR:
     92 	case IFREG:
     93 	case IFBLK:
     94 	case IFCHR:
     95 	case IFLNK:
     96 	case IFSOCK:
     97 	case IFIFO:
     98 	case IFSHAD:
     99 	case IFATTRDIR:
    100 		return (1);
    101 
    102 	default:
    103 		if (debug)
    104 			(void) printf("bad file type 0%o\n", dp->di_mode);
    105 		return (0);
    106 	}
    107 }
    108 
    109 int
    110 acltypeok(struct dinode *dp)
    111 {
    112 	if (CHECK_ACL_ALLOWED(dp->di_mode & IFMT))
    113 		return (1);
    114 
    115 	if (debug)
    116 		(void) printf("bad file type for acl I=%d: 0%o\n",
    117 		    dp->di_shadow, dp->di_mode);
    118 	return (0);
    119 }
    120 
    121 NOTE(PRINTFLIKE(1))
    122 int
    123 reply(caddr_t fmt, ...)
    124 {
    125 	va_list ap;
    126 	char line[80];
    127 
    128 	if (preen)
    129 		pfatal("INTERNAL ERROR: GOT TO reply() in preen mode");
    130 
    131 	if (mflag) {
    132 		/*
    133 		 * We don't know what's going on, so don't potentially
    134 		 * make things worse by having errexit() write stuff
    135 		 * out to disk.
    136 		 */
    137 		(void) printf(
    138 		    "\n%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
    139 		    devname);
    140 		exit(EXERRFATAL);
    141 	}
    142 
    143 	va_start(ap, fmt);
    144 	(void) putchar('\n');
    145 	(void) vprintf(fmt, ap);
    146 	(void) putchar('?');
    147 	(void) putchar(' ');
    148 	va_end(ap);
    149 
    150 	if (nflag || fswritefd < 0) {
    151 		(void) printf(" no\n\n");
    152 		return (0);
    153 	}
    154 	if (yflag) {
    155 		(void) printf(" yes\n\n");
    156 		return (1);
    157 	}
    158 	(void) fflush(stdout);
    159 	if (getline(stdin, line, sizeof (line)) == EOF)
    160 		errexit("\n");
    161 	(void) printf("\n");
    162 	if (line[0] == 'y' || line[0] == 'Y') {
    163 		return (1);
    164 	} else {
    165 		return (0);
    166 	}
    167 }
    168 
    169 int
    170 getline(FILE *fp, caddr_t loc, int maxlen)
    171 {
    172 	int n;
    173 	caddr_t p, lastloc;
    174 
    175 	p = loc;
    176 	lastloc = &p[maxlen-1];
    177 	while ((n = getc(fp)) != '\n') {
    178 		if (n == EOF)
    179 			return (EOF);
    180 		if (!isspace(n) && p < lastloc)
    181 			*p++ = (char)n;
    182 	}
    183 	*p = '\0';
    184 	/* LINTED pointer difference won't overflow */
    185 	return (p - loc);
    186 }
    187 
    188 /*
    189  * Malloc buffers and set up cache.
    190  */
    191 void
    192 bufinit(void)
    193 {
    194 	struct bufarea *bp;
    195 	int bufcnt, i;
    196 	caddr_t bufp;
    197 
    198 	bufp = malloc((size_t)sblock.fs_bsize);
    199 	if (bufp == NULL)
    200 		goto nomem;
    201 	initbarea(&cgblk);
    202 	cgblk.b_un.b_buf = bufp;
    203 	bufhead.b_next = bufhead.b_prev = &bufhead;
    204 	bufcnt = MAXBUFSPACE / sblock.fs_bsize;
    205 	if (bufcnt < MINBUFS)
    206 		bufcnt = MINBUFS;
    207 	for (i = 0; i < bufcnt; i++) {
    208 		bp = (struct bufarea *)malloc(sizeof (struct bufarea));
    209 		if (bp == NULL) {
    210 			if (i >= MINBUFS)
    211 				goto noalloc;
    212 			goto nomem;
    213 		}
    214 
    215 		bufp = malloc((size_t)sblock.fs_bsize);
    216 		if (bufp == NULL) {
    217 			free((void *)bp);
    218 			if (i >= MINBUFS)
    219 				goto noalloc;
    220 			goto nomem;
    221 		}
    222 		initbarea(bp);
    223 		bp->b_un.b_buf = bufp;
    224 		bp->b_prev = &bufhead;
    225 		bp->b_next = bufhead.b_next;
    226 		bufhead.b_next->b_prev = bp;
    227 		bufhead.b_next = bp;
    228 	}
    229 noalloc:
    230 	bufhead.b_size = i;	/* save number of buffers */
    231 	pbp = pdirbp = NULL;
    232 	return;
    233 
    234 nomem:
    235 	errexit("cannot allocate buffer pool\n");
    236 	/* NOTREACHED */
    237 }
    238 
    239 /*
    240  * Undo a bufinit().
    241  */
    242 void
    243 unbufinit(void)
    244 {
    245 	int cnt;
    246 	struct bufarea *bp, *nbp;
    247 
    248 	cnt = 0;
    249 	for (bp = bufhead.b_prev; bp != NULL && bp != &bufhead; bp = nbp) {
    250 		cnt++;
    251 		flush(fswritefd, bp);
    252 		nbp = bp->b_prev;
    253 		/*
    254 		 * We're discarding the entire chain, so this isn't
    255 		 * technically necessary.  However, it doesn't hurt
    256 		 * and lint's data flow analysis is much happier
    257 		 * (this prevents it from thinking there's a chance
    258 		 * of our using memory elsewhere after it's been released).
    259 		 */
    260 		nbp->b_next = bp->b_next;
    261 		bp->b_next->b_prev = nbp;
    262 		free((void *)bp->b_un.b_buf);
    263 		free((void *)bp);
    264 	}
    265 
    266 	if (bufhead.b_size != cnt)
    267 		errexit("Panic: cache lost %d buffers\n",
    268 		    bufhead.b_size - cnt);
    269 }
    270 
    271 /*
    272  * Manage a cache of directory blocks.
    273  */
    274 struct bufarea *
    275 getdatablk(daddr32_t blkno, size_t size)
    276 {
    277 	struct bufarea *bp;
    278 
    279 	for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
    280 		if (bp->b_bno == fsbtodb(&sblock, blkno)) {
    281 			goto foundit;
    282 		}
    283 	for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
    284 		if ((bp->b_flags & B_INUSE) == 0)
    285 			break;
    286 	if (bp == &bufhead) {
    287 		bp = alloc_bufarea();
    288 		if (bp == NULL) {
    289 			errexit("deadlocked buffer pool\n");
    290 			/* NOTREACHED */
    291 		}
    292 	}
    293 	/*
    294 	 * We're at the same logical level as getblk(), so if there
    295 	 * are any errors, we'll let our caller handle them.
    296 	 */
    297 	diskreads++;
    298 	(void) getblk(bp, blkno, size);
    299 
    300 foundit:
    301 	totalreads++;
    302 	bp->b_cnt++;
    303 	/*
    304 	 * Move the buffer to head of linked list if it isn't
    305 	 * already there.
    306 	 */
    307 	if (bufhead.b_next != bp) {
    308 		bp->b_prev->b_next = bp->b_next;
    309 		bp->b_next->b_prev = bp->b_prev;
    310 		bp->b_prev = &bufhead;
    311 		bp->b_next = bufhead.b_next;
    312 		bufhead.b_next->b_prev = bp;
    313 		bufhead.b_next = bp;
    314 	}
    315 	bp->b_flags |= B_INUSE;
    316 	return (bp);
    317 }
    318 
    319 void
    320 brelse(struct bufarea *bp)
    321 {
    322 	bp->b_cnt--;
    323 	if (bp->b_cnt == 0) {
    324 		bp->b_flags &= ~B_INUSE;
    325 	}
    326 }
    327 
    328 struct bufarea *
    329 getblk(struct bufarea *bp, daddr32_t blk, size_t size)
    330 {
    331 	diskaddr_t dblk;
    332 
    333 	dblk = fsbtodb(&sblock, blk);
    334 	if (bp->b_bno == dblk)
    335 		return (bp);
    336 	flush(fswritefd, bp);
    337 	bp->b_errs = fsck_bread(fsreadfd, bp->b_un.b_buf, dblk, size);
    338 	bp->b_bno = dblk;
    339 	bp->b_size = size;
    340 	return (bp);
    341 }
    342 
    343 void
    344 flush(int fd, struct bufarea *bp)
    345 {
    346 	int i, j;
    347 	caddr_t sip;
    348 	long size;
    349 
    350 	if (!bp->b_dirty)
    351 		return;
    352 
    353 	/*
    354 	 * It's not our buf, so if there are errors, let whoever
    355 	 * acquired it deal with the actual problem.
    356 	 */
    357 	if (bp->b_errs != 0)
    358 		pfatal("WRITING ZERO'ED BLOCK %lld TO DISK\n", bp->b_bno);
    359 	bp->b_dirty = 0;
    360 	bp->b_errs = 0;
    361 	bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
    362 	if (bp != &sblk) {
    363 		return;
    364 	}
    365 
    366 	/*
    367 	 * We're flushing the superblock, so make sure all the
    368 	 * ancillary bits go out as well.
    369 	 */
    370 	sip = (caddr_t)sblock.fs_u.fs_csp;
    371 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
    372 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
    373 		    sblock.fs_cssize - i : sblock.fs_bsize;
    374 		bwrite(fswritefd, sip,
    375 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
    376 		    size);
    377 		sip += size;
    378 	}
    379 }
    380 
    381 static void
    382 rwerror(caddr_t mesg, diskaddr_t blk, int rval)
    383 {
    384 	int olderr = errno;
    385 
    386 	if (!preen)
    387 		(void) printf("\n");
    388 
    389 	if (rval == -1)
    390 		pfatal("CANNOT %s: DISK BLOCK %lld: %s",
    391 		    mesg, blk, strerror(olderr));
    392 	else
    393 		pfatal("CANNOT %s: DISK BLOCK %lld", mesg, blk);
    394 
    395 	if (reply("CONTINUE") == 0) {
    396 		exitstat = EXERRFATAL;
    397 		errexit("Program terminated\n");
    398 	}
    399 }
    400 
    401 void
    402 ckfini(void)
    403 {
    404 	int64_t percentage;
    405 
    406 	if (fswritefd < 0)
    407 		return;
    408 
    409 	flush(fswritefd, &sblk);
    410 	/*
    411 	 * Were we using a backup superblock?
    412 	 */
    413 	if (havesb && sblk.b_bno != SBOFF / dev_bsize) {
    414 		if (preen || reply("UPDATE STANDARD SUPERBLOCK") == 1) {
    415 			sblk.b_bno = SBOFF / dev_bsize;
    416 			sbdirty();
    417 			flush(fswritefd, &sblk);
    418 		}
    419 	}
    420 	flush(fswritefd, &cgblk);
    421 	if (cgblk.b_un.b_buf != NULL) {
    422 		free((void *)cgblk.b_un.b_buf);
    423 		cgblk.b_un.b_buf = NULL;
    424 	}
    425 	unbufinit();
    426 	pbp = NULL;
    427 	pdirbp = NULL;
    428 	if (debug) {
    429 		/*
    430 		 * Note that we only count cache-related reads.
    431 		 * Anything that called fsck_bread() or getblk()
    432 		 * directly are explicitly not cached, so they're not
    433 		 * included here.
    434 		 */
    435 		if (totalreads != 0)
    436 			percentage = diskreads * 100 / totalreads;
    437 		else
    438 			percentage = 0;
    439 
    440 		(void) printf("cache missed %lld of %lld reads (%lld%%)\n",
    441 		    (longlong_t)diskreads, (longlong_t)totalreads,
    442 		    (longlong_t)percentage);
    443 	}
    444 
    445 	(void) close(fsreadfd);
    446 	(void) close(fswritefd);
    447 	fsreadfd = -1;
    448 	fswritefd = -1;
    449 }
    450 
    451 int
    452 fsck_bread(int fd, caddr_t buf, diskaddr_t blk, size_t size)
    453 {
    454 	caddr_t cp;
    455 	int i;
    456 	int errs;
    457 	offset_t offset = ldbtob(blk);
    458 	offset_t addr;
    459 
    460 	/*
    461 	 * In our universe, nothing exists before the superblock, so
    462 	 * just pretend it's always zeros.  This is the complement of
    463 	 * bwrite()'s ignoring write requests into that space.
    464 	 */
    465 	if (blk < SBLOCK) {
    466 		if (debug)
    467 			(void) printf(
    468 			    "WARNING: fsck_bread() passed blkno < %d (%lld)\n",
    469 			    SBLOCK, (longlong_t)blk);
    470 		(void) memset(buf, 0, (size_t)size);
    471 		return (1);
    472 	}
    473 
    474 	if (llseek(fd, offset, SEEK_SET) < 0) {
    475 		rwerror("SEEK", blk, -1);
    476 	}
    477 
    478 	if ((i = read(fd, buf, size)) == size) {
    479 		return (0);
    480 	}
    481 	rwerror("READ", blk, i);
    482 	if (llseek(fd, offset, SEEK_SET) < 0) {
    483 		rwerror("SEEK", blk, -1);
    484 	}
    485 	errs = 0;
    486 	(void) memset(buf, 0, (size_t)size);
    487 	pwarn("THE FOLLOWING SECTORS COULD NOT BE READ:");
    488 	for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
    489 		addr = ldbtob(blk + i);
    490 		if (llseek(fd, addr, SEEK_SET) < 0 ||
    491 		    read(fd, cp, (int)secsize) < 0) {
    492 			iscorrupt = 1;
    493 			(void) printf(" %llu", blk + (u_longlong_t)i);
    494 			errs++;
    495 		}
    496 	}
    497 	(void) printf("\n");
    498 	return (errs);
    499 }
    500 
    501 void
    502 bwrite(int fd, caddr_t buf, diskaddr_t blk, int64_t size)
    503 {
    504 	int i;
    505 	int n;
    506 	caddr_t cp;
    507 	offset_t offset = ldbtob(blk);
    508 	offset_t addr;
    509 
    510 	if (fd < 0)
    511 		return;
    512 	if (blk < SBLOCK) {
    513 		if (debug)
    514 			(void) printf(
    515 		    "WARNING: Attempt to write illegal blkno %lld on %s\n",
    516 			    (longlong_t)blk, devname);
    517 		return;
    518 	}
    519 	if (llseek(fd, offset, SEEK_SET) < 0) {
    520 		rwerror("SEEK", blk, -1);
    521 	}
    522 	if ((i = write(fd, buf, (int)size)) == size) {
    523 		fsmodified = 1;
    524 		return;
    525 	}
    526 	rwerror("WRITE", blk, i);
    527 	if (llseek(fd, offset, SEEK_SET) < 0) {
    528 		rwerror("SEEK", blk, -1);
    529 	}
    530 	pwarn("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
    531 	for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
    532 		n = 0;
    533 		addr = ldbtob(blk + i);
    534 		if (llseek(fd, addr, SEEK_SET) < 0 ||
    535 		    (n = write(fd, cp, DEV_BSIZE)) < 0) {
    536 			iscorrupt = 1;
    537 			(void) printf(" %llu", blk + (u_longlong_t)i);
    538 		} else if (n > 0) {
    539 			fsmodified = 1;
    540 		}
    541 
    542 	}
    543 	(void) printf("\n");
    544 }
    545 
    546 /*
    547  * Allocates the specified number of contiguous fragments.
    548  */
    549 daddr32_t
    550 allocblk(int wantedfrags)
    551 {
    552 	int block, leadfrag, tailfrag;
    553 	daddr32_t selected;
    554 	size_t size;
    555 	struct bufarea *bp;
    556 
    557 	/*
    558 	 * It's arguable whether we should just fail, or instead
    559 	 * error out here.  Since we should only ever be asked for
    560 	 * a single fragment or an entire block (i.e., sblock.fs_frag),
    561 	 * we'll fail out because anything else means somebody
    562 	 * changed code without considering all of the ramifications.
    563 	 */
    564 	if (wantedfrags <= 0 || wantedfrags > sblock.fs_frag) {
    565 		exitstat = EXERRFATAL;
    566 		errexit("allocblk() asked for %d frags.  "
    567 		    "Legal range is 1 to %d",
    568 		    wantedfrags, sblock.fs_frag);
    569 	}
    570 
    571 	/*
    572 	 * For each filesystem block, look at every possible starting
    573 	 * offset within the block such that we can get the number of
    574 	 * contiguous fragments that we need.  This is a drastically
    575 	 * simplified version of the kernel's mapsearch() and alloc*().
    576 	 * It's also correspondingly slower.
    577 	 */
    578 	for (block = 0; block < maxfsblock - sblock.fs_frag;
    579 	    block += sblock.fs_frag) {
    580 		for (leadfrag = 0; leadfrag <= sblock.fs_frag - wantedfrags;
    581 		    leadfrag++) {
    582 			/*
    583 			 * Is first fragment of candidate run available?
    584 			 */
    585 			if (testbmap(block + leadfrag))
    586 				continue;
    587 			/*
    588 			 * Are the rest of them available?
    589 			 */
    590 			for (tailfrag = 1; tailfrag < wantedfrags; tailfrag++)
    591 				if (testbmap(block + leadfrag + tailfrag))
    592 					break;
    593 			if (tailfrag < wantedfrags) {
    594 				/*
    595 				 * No, skip the known-unusable run.
    596 				 */
    597 				leadfrag += tailfrag;
    598 				continue;
    599 			}
    600 			/*
    601 			 * Found what we need, so claim them.
    602 			 */
    603 			for (tailfrag = 0; tailfrag < wantedfrags; tailfrag++)
    604 				setbmap(block + leadfrag + tailfrag);
    605 			n_blks += wantedfrags;
    606 			size = wantedfrags * sblock.fs_fsize;
    607 			selected = block + leadfrag;
    608 			bp = getdatablk(selected, size);
    609 			(void) memset((void *)bp->b_un.b_buf, 0, size);
    610 			dirty(bp);
    611 			brelse(bp);
    612 			if (debug)
    613 				(void) printf(
    614 		    "allocblk: selected %d (in block %d), frags %d, size %d\n",
    615 				    selected, selected % sblock.fs_bsize,
    616 				    wantedfrags, (int)size);
    617 			return (selected);
    618 		}
    619 	}
    620 	return (0);
    621 }
    622 
    623 /*
    624  * Free a previously allocated block
    625  */
    626 void
    627 freeblk(fsck_ino_t ino, daddr32_t blkno, int frags)
    628 {
    629 	struct inodesc idesc;
    630 
    631 	if (debug)
    632 		(void) printf("debug: freeing %d fragments starting at %d\n",
    633 		    frags, blkno);
    634 
    635 	init_inodesc(&idesc);
    636 
    637 	idesc.id_number = ino;
    638 	idesc.id_blkno = blkno;
    639 	idesc.id_numfrags = frags;
    640 	idesc.id_truncto = -1;
    641 
    642 	/*
    643 	 * Nothing in the return status has any relevance to how
    644 	 * we're using pass4check(), so just ignore it.
    645 	 */
    646 	(void) pass4check(&idesc);
    647 }
    648 
    649 /*
    650  * Fill NAMEBUF with a path starting in CURDIR for INO.  Assumes
    651  * that the given buffer is at least MAXPATHLEN + 1 characters.
    652  */
    653 void
    654 getpathname(caddr_t namebuf, fsck_ino_t curdir, fsck_ino_t ino)
    655 {
    656 	int len;
    657 	caddr_t cp;
    658 	struct dinode *dp;
    659 	struct inodesc idesc;
    660 	struct inoinfo *inp;
    661 
    662 	if (debug)
    663 		(void) printf("debug: getpathname(curdir %d, ino %d)\n",
    664 		    curdir, ino);
    665 
    666 	if ((curdir == 0) || (!INO_IS_DVALID(curdir))) {
    667 		(void) strcpy(namebuf, "?");
    668 		return;
    669 	}
    670 
    671 	if ((curdir == UFSROOTINO) && (ino == UFSROOTINO)) {
    672 		(void) strcpy(namebuf, "/");
    673 		return;
    674 	}
    675 
    676 	init_inodesc(&idesc);
    677 	idesc.id_type = DATA;
    678 	cp = &namebuf[MAXPATHLEN - 1];
    679 	*cp = '\0';
    680 
    681 	/*
    682 	 * In the case of extended attributes, our
    683 	 * parent won't necessarily be a directory, so just
    684 	 * return what we've found with a prefix indicating
    685 	 * that it's an XATTR.  Presumably our caller will
    686 	 * know what's going on and do something useful, like
    687 	 * work out the path of the parent and then combine
    688 	 * the two names.
    689 	 *
    690 	 * Can't use strcpy(), etc, because we've probably
    691 	 * already got some name information in the buffer and
    692 	 * the usual trailing \0 would lose it.
    693 	 */
    694 	dp = ginode(curdir);
    695 	if ((dp->di_mode & IFMT) == IFATTRDIR) {
    696 		idesc.id_number = curdir;
    697 		idesc.id_parent = ino;
    698 		idesc.id_func = findname;
    699 		idesc.id_name = namebuf;
    700 		idesc.id_fix = NOFIX;
    701 		if ((ckinode(dp, &idesc, CKI_TRAVERSE) & FOUND) == 0) {
    702 			*cp-- = '?';
    703 		}
    704 
    705 		len = sizeof (XATTR_DIR_NAME) - 1;
    706 		cp -= len;
    707 		(void) memmove(cp, XATTR_DIR_NAME, len);
    708 		goto attrname;
    709 	}
    710 
    711 	/*
    712 	 * If curdir == ino, need to get a handle on .. so we
    713 	 * can search it for ino's name.  Otherwise, just search
    714 	 * the given directory for ino.  Repeat until out of space
    715 	 * or a full path has been built.
    716 	 */
    717 	if (curdir != ino) {
    718 		idesc.id_parent = curdir;
    719 		goto namelookup;
    720 	}
    721 	while (ino != UFSROOTINO && ino != 0) {
    722 		idesc.id_number = ino;
    723 		idesc.id_func = findino;
    724 		idesc.id_name = "..";
    725 		idesc.id_fix = NOFIX;
    726 		if ((ckinode(ginode(ino), &idesc, CKI_TRAVERSE) & FOUND) == 0) {
    727 			inp = getinoinfo(ino);
    728 			if ((inp == NULL) || (inp->i_parent == 0)) {
    729 				break;
    730 			}
    731 			idesc.id_parent = inp->i_parent;
    732 		}
    733 
    734 		/*
    735 		 * To get this far, id_parent must have the inode
    736 		 * number for `..' in it.  By definition, that's got
    737 		 * to be a directory, so search it for the inode of
    738 		 * interest.
    739 		 */
    740 namelookup:
    741 		idesc.id_number = idesc.id_parent;
    742 		idesc.id_parent = ino;
    743 		idesc.id_func = findname;
    744 		idesc.id_name = namebuf;
    745 		idesc.id_fix = NOFIX;
    746 		if ((ckinode(ginode(idesc.id_number),
    747 		    &idesc, CKI_TRAVERSE) & FOUND) == 0) {
    748 			break;
    749 		}
    750 		/*
    751 		 * Prepend to what we've accumulated so far.  If
    752 		 * there's not enough room for even one more path element
    753 		 * (of the worst-case length), then bail out.
    754 		 */
    755 		len = strlen(namebuf);
    756 		cp -= len;
    757 		if (cp < &namebuf[MAXNAMLEN])
    758 			break;
    759 		(void) memmove(cp, namebuf, len);
    760 		*--cp = '/';
    761 
    762 		/*
    763 		 * Corner case for a looped-to-itself directory.
    764 		 */
    765 		if (ino == idesc.id_number)
    766 			break;
    767 
    768 		/*
    769 		 * Climb one level of the hierarchy.  In other words,
    770 		 * the current .. becomes the inode to search for and
    771 		 * its parent becomes the directory to search in.
    772 		 */
    773 		ino = idesc.id_number;
    774 	}
    775 
    776 	/*
    777 	 * If we hit a discontinuity in the hierarchy, indicate it by
    778 	 * prefixing the path so far with `?'.  Otherwise, the first
    779 	 * character will be `/' as a side-effect of the *--cp above.
    780 	 *
    781 	 * The special case is to handle the situation where we're
    782 	 * trying to look something up in UFSROOTINO, but didn't find
    783 	 * it.
    784 	 */
    785 	if (ino != UFSROOTINO || cp == &namebuf[MAXPATHLEN - 1]) {
    786 		if (cp > namebuf)
    787 			cp--;
    788 		*cp = '?';
    789 	}
    790 
    791 	/*
    792 	 * The invariants being used for buffer integrity are:
    793 	 * - namebuf[] is terminated with \0 before anything else
    794 	 * - cp is always <= the last element of namebuf[]
    795 	 * - the new path element is always stored at the
    796 	 *   beginning of namebuf[], and is no more than MAXNAMLEN-1
    797 	 *   characters
    798 	 * - cp is is decremented by the number of characters in
    799 	 *   the new path element
    800 	 * - if, after the above accounting for the new element's
    801 	 *   size, there is no longer enough room at the beginning of
    802 	 *   namebuf[] for a full-sized path element and a slash,
    803 	 *   terminate the loop.  cp is in the range
    804 	 *   &namebuf[0]..&namebuf[MAXNAMLEN - 1]
    805 	 */
    806 attrname:
    807 	/* LINTED per the above discussion */
    808 	(void) memmove(namebuf, cp, &namebuf[MAXPATHLEN] - cp);
    809 }
    810 
    811 /* ARGSUSED */
    812 void
    813 catch(int dummy)
    814 {
    815 	ckfini();
    816 	exit(EXSIGNAL);
    817 }
    818 
    819 /*
    820  * When preening, allow a single quit to signal
    821  * a special exit after filesystem checks complete
    822  * so that reboot sequence may be interrupted.
    823  */
    824 /* ARGSUSED */
    825 void
    826 catchquit(int dummy)
    827 {
    828 	(void) printf("returning to single-user after filesystem check\n");
    829 	interrupted = 1;
    830 	(void) signal(SIGQUIT, SIG_DFL);
    831 }
    832 
    833 
    834 /*
    835  * determine whether an inode should be fixed.
    836  */
    837 NOTE(PRINTFLIKE(2))
    838 int
    839 dofix(struct inodesc *idesc, caddr_t msg, ...)
    840 {
    841 	int rval = 0;
    842 	va_list ap;
    843 
    844 	va_start(ap, msg);
    845 
    846 	switch (idesc->id_fix) {
    847 
    848 	case DONTKNOW:
    849 		if (idesc->id_type == DATA)
    850 			vdirerror(idesc->id_number, msg, ap);
    851 		else
    852 			vpwarn(msg, ap);
    853 		if (preen) {
    854 			idesc->id_fix = FIX;
    855 			rval = ALTERED;
    856 			break;
    857 		}
    858 		if (reply("SALVAGE") == 0) {
    859 			idesc->id_fix = NOFIX;
    860 			break;
    861 		}
    862 		idesc->id_fix = FIX;
    863 		rval = ALTERED;
    864 		break;
    865 
    866 	case FIX:
    867 		rval = ALTERED;
    868 		break;
    869 
    870 	case NOFIX:
    871 		break;
    872 
    873 	default:
    874 		errexit("UNKNOWN INODESC FIX MODE %d\n", (int)idesc->id_fix);
    875 	}
    876 
    877 	va_end(ap);
    878 	return (rval);
    879 }
    880 
    881 NOTE(PRINTFLIKE(1))
    882 void
    883 errexit(caddr_t fmt, ...)
    884 {
    885 	va_list ap;
    886 
    887 	va_start(ap, fmt);
    888 	verrexit(fmt, ap);
    889 	/* NOTREACHED */
    890 }
    891 
    892 NOTE(PRINTFLIKE(1))
    893 static void
    894 verrexit(caddr_t fmt, va_list ap)
    895 {
    896 	static int recursing = 0;
    897 
    898 	if (!recursing) {
    899 		recursing = 1;
    900 		if (errorlocked || iscorrupt) {
    901 			if (havesb && fswritefd >= 0) {
    902 				sblock.fs_clean = FSBAD;
    903 				sblock.fs_state = FSOKAY - (long)sblock.fs_time;
    904 				sblock.fs_state = -sblock.fs_state;
    905 				sbdirty();
    906 				write_altsb(fswritefd);
    907 				flush(fswritefd, &sblk);
    908 			}
    909 		}
    910 		ckfini();
    911 		recursing = 0;
    912 	}
    913 	(void) vprintf(fmt, ap);
    914 	if (fmt[strlen(fmt) - 1] != '\n')
    915 		(void) putchar('\n');
    916 	exit((exitstat != 0) ? exitstat : EXERRFATAL);
    917 }
    918 
    919 /*
    920  * An unexpected inconsistency occured.
    921  * Die if preening, otherwise just print message and continue.
    922  */
    923 NOTE(PRINTFLIKE(1))
    924 void
    925 pfatal(caddr_t fmt, ...)
    926 {
    927 	va_list ap;
    928 
    929 	va_start(ap, fmt);
    930 	vpfatal(fmt, ap);
    931 	va_end(ap);
    932 }
    933 
    934 NOTE(PRINTFLIKE(1))
    935 static void
    936 vpfatal(caddr_t fmt, va_list ap)
    937 {
    938 	if (preen) {
    939 		if (*fmt != '\0') {
    940 			(void) printf("%s: ", devname);
    941 			(void) vprintf(fmt, ap);
    942 			(void) printf("\n");
    943 		}
    944 		(void) printf(
    945 		    "%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
    946 		    devname);
    947 		if (havesb && fswritefd >= 0) {
    948 			sblock.fs_clean = FSBAD;
    949 			sblock.fs_state = -(FSOKAY - (long)sblock.fs_time);
    950 			sbdirty();
    951 			flush(fswritefd, &sblk);
    952 		}
    953 		/*
    954 		 * We're exiting, it doesn't really matter that our
    955 		 * caller doesn't get to call va_end().
    956 		 */
    957 		if (exitstat == 0)
    958 			exitstat = EXFNDERRS;
    959 		exit(exitstat);
    960 	}
    961 	if (*fmt != '\0') {
    962 		(void) vprintf(fmt, ap);
    963 	}
    964 }
    965 
    966 /*
    967  * Pwarn just prints a message when not preening,
    968  * or a warning (preceded by filename) when preening.
    969  */
    970 NOTE(PRINTFLIKE(1))
    971 void
    972 pwarn(caddr_t fmt, ...)
    973 {
    974 	va_list ap;
    975 
    976 	va_start(ap, fmt);
    977 	vpwarn(fmt, ap);
    978 	va_end(ap);
    979 }
    980 
    981 NOTE(PRINTFLIKE(1))
    982 static void
    983 vpwarn(caddr_t fmt, va_list ap)
    984 {
    985 	if (*fmt != '\0') {
    986 		if (preen)
    987 			(void) printf("%s: ", devname);
    988 		(void) vprintf(fmt, ap);
    989 	}
    990 }
    991 
    992 /*
    993  * Like sprintf(), except the buffer is dynamically allocated
    994  * and returned, instead of being passed in.  A pointer to the
    995  * buffer is stored in *RET, and FMT is the usual format string.
    996  * The number of characters in *RET (excluding the trailing \0,
    997  * to be consistent with the other *printf() routines) is returned.
    998  *
    999  * Solaris doesn't have asprintf(3C) yet, unfortunately.
   1000  */
   1001 NOTE(PRINTFLIKE(2))
   1002 int
   1003 fsck_asprintf(caddr_t *ret, caddr_t fmt, ...)
   1004 {
   1005 	int len;
   1006 	caddr_t buffer;
   1007 	va_list ap;
   1008 
   1009 	va_start(ap, fmt);
   1010 	len = vsnprintf(NULL, 0, fmt, ap);
   1011 	va_end(ap);
   1012 
   1013 	buffer = malloc((len + 1) * sizeof (char));
   1014 	if (buffer == NULL) {
   1015 		errexit("Out of memory in asprintf\n");
   1016 		/* NOTREACHED */
   1017 	}
   1018 
   1019 	va_start(ap, fmt);
   1020 	(void) vsnprintf(buffer, len + 1, fmt, ap);
   1021 	va_end(ap);
   1022 
   1023 	*ret = buffer;
   1024 	return (len);
   1025 }
   1026 
   1027 /*
   1028  * So we can take advantage of kernel routines in ufs_subr.c.
   1029  */
   1030 /* PRINTFLIKE2 */
   1031 void
   1032 cmn_err(int level, caddr_t fmt, ...)
   1033 {
   1034 	va_list ap;
   1035 
   1036 	va_start(ap, fmt);
   1037 	if (level == CE_PANIC) {
   1038 		(void) printf("INTERNAL INCONSISTENCY:");
   1039 		verrexit(fmt, ap);
   1040 	} else {
   1041 		(void) vprintf(fmt, ap);
   1042 	}
   1043 	va_end(ap);
   1044 }
   1045 
   1046 /*
   1047  * Check to see if unraw version of name is already mounted.
   1048  * Updates devstr with the device name if devstr is not NULL
   1049  * and str_size is positive.
   1050  */
   1051 int
   1052 mounted(caddr_t name, caddr_t devstr, size_t str_size)
   1053 {
   1054 	int found;
   1055 	struct mnttab *mntent;
   1056 
   1057 	mntent = search_mnttab(NULL, unrawname(name), devstr, str_size);
   1058 	if (mntent == NULL)
   1059 		return (M_NOMNT);
   1060 
   1061 	/*
   1062 	 * It's mounted.  With or without write access?
   1063 	 */
   1064 	if (hasmntopt(mntent, MNTOPT_RO) != 0)
   1065 		found = M_RO;	/* mounted as RO */
   1066 	else
   1067 		found = M_RW; 	/* mounted as R/W */
   1068 
   1069 	if (mount_point == NULL) {
   1070 		mount_point = strdup(mntent->mnt_mountp);
   1071 		if (mount_point == NULL) {
   1072 			errexit("fsck: memory allocation failure: %s",
   1073 			    strerror(errno));
   1074 			/* NOTREACHED */
   1075 		}
   1076 
   1077 		if (devstr != NULL && str_size > 0)
   1078 			(void) strlcpy(devstr, mntent->mnt_special, str_size);
   1079 	}
   1080 
   1081 	return (found);
   1082 }
   1083 
   1084 /*
   1085  * Check to see if name corresponds to an entry in vfstab, and that the entry
   1086  * does not have option ro.
   1087  */
   1088 int
   1089 writable(caddr_t name)
   1090 {
   1091 	int rw = 1;
   1092 	struct vfstab vfsbuf, vfskey;
   1093 	FILE *vfstab;
   1094 
   1095 	vfstab = fopen(VFSTAB, "r");
   1096 	if (vfstab == NULL) {
   1097 		(void) printf("can't open %s\n", VFSTAB);
   1098 		return (1);
   1099 	}
   1100 	(void) memset((void *)&vfskey, 0, sizeof (vfskey));
   1101 	vfsnull(&vfskey);
   1102 	vfskey.vfs_special = unrawname(name);
   1103 	vfskey.vfs_fstype = MNTTYPE_UFS;
   1104 	if ((getvfsany(vfstab, &vfsbuf, &vfskey) == 0) &&
   1105 	    (hasvfsopt(&vfsbuf, MNTOPT_RO))) {
   1106 		rw = 0;
   1107 	}
   1108 	(void) fclose(vfstab);
   1109 	return (rw);
   1110 }
   1111 
   1112 /*
   1113  * debugclean
   1114  */
   1115 static void
   1116 debugclean(void)
   1117 {
   1118 	if (!debug)
   1119 		return;
   1120 
   1121 	if ((iscorrupt == 0) && (isdirty == 0))
   1122 		return;
   1123 
   1124 	if ((sblock.fs_clean == FSSTABLE) || (sblock.fs_clean == FSCLEAN) ||
   1125 	    (sblock.fs_clean == FSLOG && islog && islogok) ||
   1126 	    ((FSOKAY == (sblock.fs_state + sblock.fs_time)) && !errorlocked))
   1127 		return;
   1128 
   1129 	(void) printf("WARNING: inconsistencies detected on %s filesystem %s\n",
   1130 	    sblock.fs_clean == FSSTABLE ? "stable" :
   1131 	    sblock.fs_clean == FSLOG ? "logging" :
   1132 	    sblock.fs_clean == FSFIX ? "being fixed" : "clean",
   1133 	    devname);
   1134 }
   1135 
   1136 /*
   1137  * updateclean
   1138  *	Carefully and transparently update the clean flag.
   1139  *
   1140  * `iscorrupt' has to be in its final state before this is called.
   1141  */
   1142 int
   1143 updateclean(void)
   1144 {
   1145 	int freedlog = 0;
   1146 	struct bufarea cleanbuf;
   1147 	size_t size;
   1148 	ssize_t io_res;
   1149 	diskaddr_t bno;
   1150 	char fsclean;
   1151 	int fsreclaim;
   1152 	char fsflags;
   1153 	int flags_ok = 1;
   1154 	daddr32_t fslogbno;
   1155 	offset_t sblkoff;
   1156 	time_t t;
   1157 
   1158 	/*
   1159 	 * debug stuff
   1160 	 */
   1161 	debugclean();
   1162 
   1163 	/*
   1164 	 * set fsclean to its appropriate value
   1165 	 */
   1166 	fslogbno = sblock.fs_logbno;
   1167 	fsclean = sblock.fs_clean;
   1168 	fsreclaim = sblock.fs_reclaim;
   1169 	fsflags = sblock.fs_flags;
   1170 	if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked) {
   1171 		fsclean = FSACTIVE;
   1172 	}
   1173 	/*
   1174 	 * If ufs log is not okay, note that we need to clear it.
   1175 	 */
   1176 	examinelog(NULL);
   1177 	if (fslogbno && !(islog && islogok)) {
   1178 		fsclean = FSACTIVE;
   1179 		fslogbno = 0;
   1180 	}
   1181 
   1182 	/*
   1183 	 * if necessary, update fs_clean and fs_state
   1184 	 */
   1185 	switch (fsclean) {
   1186 
   1187 	case FSACTIVE:
   1188 		if (!iscorrupt) {
   1189 			fsclean = FSSTABLE;
   1190 			fsreclaim = 0;
   1191 		}
   1192 		break;
   1193 
   1194 	case FSCLEAN:
   1195 	case FSSTABLE:
   1196 		if (iscorrupt) {
   1197 			fsclean = FSACTIVE;
   1198 		} else {
   1199 			fsreclaim = 0;
   1200 		}
   1201 		break;
   1202 
   1203 	case FSLOG:
   1204 		if (iscorrupt) {
   1205 			fsclean = FSACTIVE;
   1206 		} else if (!islog || fslogbno == 0) {
   1207 			fsclean = FSSTABLE;
   1208 			fsreclaim = 0;
   1209 		} else if (fflag) {
   1210 			fsreclaim = 0;
   1211 		}
   1212 		break;
   1213 
   1214 	case FSFIX:
   1215 		fsclean = FSBAD;
   1216 		if (errorlocked && !iscorrupt) {
   1217 			fsclean = islog ? FSLOG : FSCLEAN;
   1218 		}
   1219 		break;
   1220 
   1221 	default:
   1222 		if (iscorrupt) {
   1223 			fsclean = FSACTIVE;
   1224 		} else {
   1225 			fsclean = FSSTABLE;
   1226 			fsreclaim = 0;
   1227 		}
   1228 	}
   1229 
   1230 	if (largefile_count > 0)
   1231 		fsflags |= FSLARGEFILES;
   1232 	else
   1233 		fsflags &= ~FSLARGEFILES;
   1234 
   1235 	/*
   1236 	 * There can be two discrepencies here.  A) The superblock
   1237 	 * shows no largefiles but we found some while scanning.
   1238 	 * B) The superblock indicates the presence of largefiles,
   1239 	 * but none are present.  Note that if preening, the superblock
   1240 	 * is silently corrected.
   1241 	 */
   1242 	if ((fsflags == FSLARGEFILES && sblock.fs_flags != FSLARGEFILES) ||
   1243 	    (fsflags != FSLARGEFILES && sblock.fs_flags == FSLARGEFILES))
   1244 		flags_ok = 0;
   1245 
   1246 	if (debug)
   1247 		(void) printf(
   1248 		    "** largefile count=%d, fs.fs_flags=%x, flags_ok %d\n",
   1249 		    largefile_count, sblock.fs_flags, flags_ok);
   1250 
   1251 	/*
   1252 	 * If fs is unchanged, do nothing.
   1253 	 */
   1254 	if ((!isdirty) && (flags_ok) &&
   1255 	    (fslogbno == sblock.fs_logbno) &&
   1256 	    (sblock.fs_clean == fsclean) &&
   1257 	    (sblock.fs_reclaim == fsreclaim) &&
   1258 	    (FSOKAY == (sblock.fs_state + sblock.fs_time))) {
   1259 		if (errorlocked) {
   1260 			if (!do_errorlock(LOCKFS_ULOCK))
   1261 				pwarn(
   1262 		    "updateclean(unchanged): unlock(LOCKFS_ULOCK) failed\n");
   1263 		}
   1264 		return (freedlog);
   1265 	}
   1266 
   1267 	/*
   1268 	 * if user allows, update superblock state
   1269 	 */
   1270 	if (debug) {
   1271 		(void) printf(
   1272 	    "superblock: flags 0x%x logbno %d clean %d reclaim %d state 0x%x\n",
   1273 		    sblock.fs_flags, sblock.fs_logbno,
   1274 		    sblock.fs_clean, sblock.fs_reclaim,
   1275 		    sblock.fs_state + sblock.fs_time);
   1276 		(void) printf(
   1277 	    "calculated: flags 0x%x logbno %d clean %d reclaim %d state 0x%x\n",
   1278 		    fsflags, fslogbno, fsclean, fsreclaim, FSOKAY);
   1279 	}
   1280 	if (!isdirty && !preen && !rerun &&
   1281 	    (reply("FILE SYSTEM STATE IN SUPERBLOCK IS WRONG; FIX") == 0))
   1282 		return (freedlog);
   1283 
   1284 	(void) time(&t);
   1285 	sblock.fs_time = (time32_t)t;
   1286 	if (debug)
   1287 		printclean();
   1288 
   1289 	if (sblock.fs_logbno != fslogbno) {
   1290 		examinelog(&freelogblk);
   1291 		freedlog++;
   1292 	}
   1293 
   1294 	sblock.fs_logbno = fslogbno;
   1295 	sblock.fs_clean = fsclean;
   1296 	sblock.fs_state = FSOKAY - (long)sblock.fs_time;
   1297 	sblock.fs_reclaim = fsreclaim;
   1298 	sblock.fs_flags = fsflags;
   1299 
   1300 	/*
   1301 	 * if superblock can't be written, return
   1302 	 */
   1303 	if (fswritefd < 0)
   1304 		return (freedlog);
   1305 
   1306 	/*
   1307 	 * Read private copy of superblock, update clean flag, and write it.
   1308 	 */
   1309 	bno  = sblk.b_bno;
   1310 	size = sblk.b_size;
   1311 
   1312 	sblkoff = ldbtob(bno);
   1313 
   1314 	if ((cleanbuf.b_un.b_buf = malloc(size)) == NULL)
   1315 		errexit("out of memory");
   1316 	if (llseek(fsreadfd, sblkoff, SEEK_SET) == -1) {
   1317 		(void) printf("COULD NOT SEEK TO SUPERBLOCK AT %lld: %s\n",
   1318 		    (longlong_t)bno, strerror(errno));
   1319 		goto out;
   1320 	}
   1321 
   1322 	if ((io_res = read(fsreadfd, cleanbuf.b_un.b_buf, size)) != size) {
   1323 		report_io_prob("READ FROM", bno, size, io_res);
   1324 		goto out;
   1325 	}
   1326 
   1327 	cleanbuf.b_un.b_fs->fs_logbno  = sblock.fs_logbno;
   1328 	cleanbuf.b_un.b_fs->fs_clean   = sblock.fs_clean;
   1329 	cleanbuf.b_un.b_fs->fs_state   = sblock.fs_state;
   1330 	cleanbuf.b_un.b_fs->fs_time    = sblock.fs_time;
   1331 	cleanbuf.b_un.b_fs->fs_reclaim = sblock.fs_reclaim;
   1332 	cleanbuf.b_un.b_fs->fs_flags   = sblock.fs_flags;
   1333 
   1334 	if (llseek(fswritefd, sblkoff, SEEK_SET) == -1) {
   1335 		(void) printf("COULD NOT SEEK TO SUPERBLOCK AT %lld: %s\n",
   1336 		    (longlong_t)bno, strerror(errno));
   1337 		goto out;
   1338 	}
   1339 
   1340 	if ((io_res = write(fswritefd, cleanbuf.b_un.b_buf, size)) != size) {
   1341 		report_io_prob("WRITE TO", bno, size, io_res);
   1342 		goto out;
   1343 	}
   1344 
   1345 	/*
   1346 	 * 1208040
   1347 	 * If we had to use -b to grab an alternate superblock, then we
   1348 	 * likely had to do so because of unacceptable differences between
   1349 	 * the main and alternate superblocks.  So, we had better update
   1350 	 * the alternate superblock as well, or we'll just fail again
   1351 	 * the next time we attempt to run fsck!
   1352 	 */
   1353 	if (bflag != 0) {
   1354 		write_altsb(fswritefd);
   1355 	}
   1356 
   1357 	if (errorlocked) {
   1358 		if (!do_errorlock(LOCKFS_ULOCK))
   1359 			pwarn(
   1360 		    "updateclean(changed): unlock(LOCKFS_ULOCK) failed\n");
   1361 	}
   1362 
   1363 out:
   1364 	if (cleanbuf.b_un.b_buf != NULL) {
   1365 		free((void *)cleanbuf.b_un.b_buf);
   1366 	}
   1367 
   1368 	return (freedlog);
   1369 }
   1370 
   1371 static void
   1372 report_io_prob(caddr_t what, diskaddr_t bno, size_t expected, ssize_t failure)
   1373 {
   1374 	if (failure < 0)
   1375 		(void) printf("COULD NOT %s SUPERBLOCK AT %d: %s\n",
   1376 		    what, (int)bno, strerror(errno));
   1377 	else if (failure == 0)
   1378 		(void) printf("COULD NOT %s SUPERBLOCK AT %d: EOF\n",
   1379 		    what, (int)bno);
   1380 	else
   1381 		(void) printf("SHORT %s SUPERBLOCK AT %d: %u out of %u bytes\n",
   1382 		    what, (int)bno, (unsigned)failure, (unsigned)expected);
   1383 }
   1384 
   1385 /*
   1386  * print out clean info
   1387  */
   1388 void
   1389 printclean(void)
   1390 {
   1391 	caddr_t s;
   1392 
   1393 	if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked)
   1394 		s = "unknown";
   1395 	else
   1396 		switch (sblock.fs_clean) {
   1397 
   1398 		case FSACTIVE:
   1399 			s = "active";
   1400 			break;
   1401 
   1402 		case FSCLEAN:
   1403 			s = "clean";
   1404 			break;
   1405 
   1406 		case FSSTABLE:
   1407 			s = "stable";
   1408 			break;
   1409 
   1410 		case FSLOG:
   1411 			s = "logging";
   1412 			break;
   1413 
   1414 		case FSBAD:
   1415 			s = "is bad";
   1416 			break;
   1417 
   1418 		case FSFIX:
   1419 			s = "being fixed";
   1420 			break;
   1421 
   1422 		default:
   1423 			s = "unknown";
   1424 		}
   1425 
   1426 	if (preen)
   1427 		pwarn("is %s.\n", s);
   1428 	else
   1429 		(void) printf("** %s is %s.\n", devname, s);
   1430 }
   1431 
   1432 int
   1433 is_errorlocked(caddr_t fs)
   1434 {
   1435 	int		retval;
   1436 	struct stat64	statb;
   1437 	caddr_t		mountp;
   1438 	struct mnttab	*mntent;
   1439 
   1440 	retval = 0;
   1441 
   1442 	if (!fs)
   1443 		return (0);
   1444 
   1445 	if (stat64(fs, &statb) < 0)
   1446 		return (0);
   1447 
   1448 	if (S_ISDIR(statb.st_mode)) {
   1449 		mountp = fs;
   1450 	} else if (S_ISBLK(statb.st_mode) || S_ISCHR(statb.st_mode)) {
   1451 		mntent = search_mnttab(NULL, fs, NULL, 0);
   1452 		if (mntent == NULL)
   1453 			return (0);
   1454 		mountp = mntent->mnt_mountp;
   1455 		if (mountp == NULL) /* theoretically a can't-happen */
   1456 			return (0);
   1457 	} else {
   1458 		return (0);
   1459 	}
   1460 
   1461 	/*
   1462 	 * From here on, must `goto out' to avoid memory leakage.
   1463 	 */
   1464 
   1465 	if (elock_combuf == NULL)
   1466 		elock_combuf =
   1467 		    (caddr_t)calloc(LOCKFS_MAXCOMMENTLEN, sizeof (char));
   1468 	else
   1469 		elock_combuf =
   1470 		    (caddr_t)realloc(elock_combuf, LOCKFS_MAXCOMMENTLEN);
   1471 
   1472 	if (elock_combuf == NULL)
   1473 		goto out;
   1474 
   1475 	(void) memset((void *)elock_combuf, 0, LOCKFS_MAXCOMMENTLEN);
   1476 
   1477 	if (elock_mountp != NULL) {
   1478 		free(elock_mountp);
   1479 	}
   1480 
   1481 	elock_mountp = strdup(mountp);
   1482 	if (elock_mountp == NULL)
   1483 		goto out;
   1484 
   1485 	if (mountfd < 0) {
   1486 		if ((mountfd = open64(mountp, O_RDONLY)) == -1)
   1487 			goto out;
   1488 	}
   1489 
   1490 	if (lfp == NULL) {
   1491 		lfp = (struct lockfs *)malloc(sizeof (struct lockfs));
   1492 		if (lfp == NULL)
   1493 			goto out;
   1494 		(void) memset((void *)lfp, 0, sizeof (struct lockfs));
   1495 	}
   1496 
   1497 	lfp->lf_comlen = LOCKFS_MAXCOMMENTLEN;
   1498 	lfp->lf_comment = elock_combuf;
   1499 
   1500 	if (ioctl(mountfd, _FIOLFSS, lfp) == -1)
   1501 		goto out;
   1502 
   1503 	/*
   1504 	 * lint believes that the ioctl() (or any other function
   1505 	 * taking lfp as an arg) could free lfp.  This is not the
   1506 	 * case, however.
   1507 	 */
   1508 	retval = LOCKFS_IS_ELOCK(lfp);
   1509 
   1510 out:
   1511 	return (retval);
   1512 }
   1513 
   1514 /*
   1515  * Given a name which is known to be a directory, see if it appears
   1516  * in the vfstab.  If so, return the entry's block (special) device
   1517  * field via devstr.
   1518  */
   1519 int
   1520 check_vfstab(caddr_t name, caddr_t devstr, size_t str_size)
   1521 {
   1522 	return (NULL != search_vfstab(name, NULL, devstr, str_size));
   1523 }
   1524 
   1525 /*
   1526  * Given a name which is known to be a directory, see if it appears
   1527  * in the mnttab.  If so, return the entry's block (special) device
   1528  * field via devstr.
   1529  */
   1530 int
   1531 check_mnttab(caddr_t name, caddr_t devstr, size_t str_size)
   1532 {
   1533 	return (NULL != search_mnttab(name, NULL, devstr, str_size));
   1534 }
   1535 
   1536 /*
   1537  * Search for mount point and/or special device in the given file.
   1538  * The first matching entry is returned.
   1539  *
   1540  * If an entry is found and str_size is greater than zero, then
   1541  * up to size_str bytes of the special device name from the entry
   1542  * are copied to devstr.
   1543  */
   1544 
   1545 #define	SEARCH_TAB_BODY(st_type, st_file, st_mount, st_special, \
   1546 			st_nuller, st_init, st_searcher) \
   1547 	{ \
   1548 		FILE *fp; \
   1549 		struct st_type *retval = NULL; \
   1550 		struct st_type key; \
   1551 		static struct st_type buffer; \
   1552 		\
   1553 		/* LINTED ``assigned value never used'' */ \
   1554 		st_nuller(&key); \
   1555 		key.st_mount = mountp; \
   1556 		key.st_special = special; \
   1557 		st_init; \
   1558 		\
   1559 		if ((fp = fopen(st_file, "r")) == NULL) \
   1560 			return (NULL); \
   1561 		\
   1562 		if (st_searcher(fp, &buffer, &key) == 0) { \
   1563 			retval = &buffer; \
   1564 			if (devstr != NULL && str_size > 0 && \
   1565 			    buffer.st_special != NULL) { \
   1566 				(void) strlcpy(devstr, buffer.st_special, \
   1567 				    str_size); \
   1568 			} \
   1569 		} \
   1570 		(void) fclose(fp); \
   1571 		return (retval); \
   1572 	}
   1573 
   1574 static struct vfstab *
   1575 search_vfstab(caddr_t mountp, caddr_t special, caddr_t devstr, size_t str_size)
   1576 SEARCH_TAB_BODY(vfstab, VFSTAB, vfs_mountp, vfs_special, vfsnull,
   1577 		(retval = retval), getvfsany)
   1578 
   1579 static struct mnttab *
   1580 search_mnttab(caddr_t mountp, caddr_t special, caddr_t devstr, size_t str_size)
   1581 SEARCH_TAB_BODY(mnttab, MNTTAB, mnt_mountp, mnt_special, mntnull,
   1582 		(key.mnt_fstype = MNTTYPE_UFS), getmntany)
   1583 
   1584 int
   1585 do_errorlock(int lock_type)
   1586 {
   1587 	caddr_t	   buf;
   1588 	time_t	   now;
   1589 	struct tm *local;
   1590 	int	   rc;
   1591 
   1592 	if (elock_combuf == NULL)
   1593 		errexit("do_errorlock(%s, %d): unallocated elock_combuf\n",
   1594 		    elock_mountp ? elock_mountp : "<null>",
   1595 		    lock_type);
   1596 
   1597 	if ((buf = (caddr_t)calloc(LOCKFS_MAXCOMMENTLEN, sizeof (char))) ==
   1598 	    NULL) {
   1599 		errexit("Couldn't alloc memory for temp. lock status buffer\n");
   1600 	}
   1601 	if (lfp == NULL) {
   1602 		errexit("do_errorlock(%s, %d): lockfs status unallocated\n",
   1603 		    elock_mountp, lock_type);
   1604 	}
   1605 
   1606 	(void) memmove((void *)buf, (void *)elock_combuf,
   1607 	    LOCKFS_MAXCOMMENTLEN-1);
   1608 
   1609 	switch (lock_type) {
   1610 	case LOCKFS_ELOCK:
   1611 		/*
   1612 		 * Note that if it is error-locked, we won't get an
   1613 		 * error back if we try to error-lock it again.
   1614 		 */
   1615 		if (time(&now) != (time_t)-1) {
   1616 			if ((local = localtime(&now)) != NULL)
   1617 				(void) snprintf(buf, LOCKFS_MAXCOMMENTLEN,
   1618 		    "%s [pid:%d fsck start:%02d/%02d/%02d %02d:%02d:%02d",
   1619 				    elock_combuf, (int)pid,
   1620 				    local->tm_mon + 1, local->tm_mday,
   1621 				    (local->tm_year % 100), local->tm_hour,
   1622 				    local->tm_min, local->tm_sec);
   1623 			else
   1624 				(void) snprintf(buf, LOCKFS_MAXCOMMENTLEN,
   1625 				    "%s [fsck pid %d", elock_combuf, pid);
   1626 
   1627 		} else {
   1628 			(void) snprintf(buf, LOCKFS_MAXCOMMENTLEN,
   1629 			    "%s [fsck pid %d", elock_combuf, pid);
   1630 		}
   1631 		break;
   1632 
   1633 	case LOCKFS_ULOCK:
   1634 		if (time(&now) != (time_t)-1) {
   1635 			if ((local = localtime(&now)) != NULL) {
   1636 				(void) snprintf(buf, LOCKFS_MAXCOMMENTLEN,
   1637 				    "%s, done:%02d/%02d/%02d %02d:%02d:%02d]",
   1638 				    elock_combuf,
   1639 				    local->tm_mon + 1, local->tm_mday,
   1640 				    (local->tm_year % 100), local->tm_hour,
   1641 				    local->tm_min, local->tm_sec);
   1642 			} else {
   1643 				(void) snprintf(buf, LOCKFS_MAXCOMMENTLEN,
   1644 				    "%s]", elock_combuf);
   1645 			}
   1646 		} else {
   1647 			(void) snprintf(buf, LOCKFS_MAXCOMMENTLEN,
   1648 			    "%s]", elock_combuf);
   1649 		}
   1650 		if ((rc = ioctl(mountfd, _FIOLFSS, lfp)) == -1) {
   1651 			pwarn("do_errorlock: unlock failed: %s\n",
   1652 			    strerror(errno));
   1653 			goto out;
   1654 		}
   1655 		break;
   1656 
   1657 	default:
   1658 		break;
   1659 	}
   1660 
   1661 	(void) memmove((void *)elock_combuf, (void *)buf,
   1662 	    LOCKFS_MAXCOMMENTLEN - 1);
   1663 
   1664 	lfp->lf_lock = lock_type;
   1665 	lfp->lf_comlen = LOCKFS_MAXCOMMENTLEN;
   1666 	lfp->lf_comment = elock_combuf;
   1667 	lfp->lf_flags = 0;
   1668 	errno = 0;
   1669 
   1670 	if ((rc = ioctl(mountfd, _FIOLFS, lfp)) == -1) {
   1671 		if (errno == EINVAL) {
   1672 			pwarn("Another fsck active?\n");
   1673 			iscorrupt = 0;	/* don't go away mad, just go away */
   1674 		} else {
   1675 			pwarn("do_errorlock(lock_type:%d, %s) failed: %s\n",
   1676 			    lock_type, elock_combuf, strerror(errno));
   1677 		}
   1678 	}
   1679 out:
   1680 	if (buf != NULL) {
   1681 		free((void *)buf);
   1682 	}
   1683 
   1684 	return (rc != -1);
   1685 }
   1686 
   1687 /*
   1688  * Shadow inode support.  To register a shadow with a client is to note
   1689  * that an inode (the client) refers to the shadow.
   1690  */
   1691 
   1692 static struct shadowclients *
   1693 newshadowclient(struct shadowclients *prev)
   1694 {
   1695 	struct shadowclients *rc;
   1696 
   1697 	rc = (struct shadowclients *)malloc(sizeof (*rc));
   1698 	if (rc == NULL)
   1699 		errexit("newshadowclient: cannot malloc shadow client");
   1700 	rc->next = prev;
   1701 	rc->nclients = 0;
   1702 
   1703 	rc->client = (fsck_ino_t *)malloc(sizeof (fsck_ino_t) *
   1704 	    maxshadowclients);
   1705 	if (rc->client == NULL)
   1706 		errexit("newshadowclient: cannot malloc client array");
   1707 	return (rc);
   1708 }
   1709 
   1710 void
   1711 registershadowclient(fsck_ino_t shadow, fsck_ino_t client,
   1712 	struct shadowclientinfo **info)
   1713 {
   1714 	struct shadowclientinfo *sci;
   1715 	struct shadowclients *scc;
   1716 
   1717 	/*
   1718 	 * Already have a record for this shadow?
   1719 	 */
   1720 	for (sci = *info; sci != NULL; sci = sci->next)
   1721 		if (sci->shadow == shadow)
   1722 			break;
   1723 	if (sci == NULL) {
   1724 		/*
   1725 		 * It's a new shadow, add it to the list
   1726 		 */
   1727 		sci = (struct shadowclientinfo *)malloc(sizeof (*sci));
   1728 		if (sci == NULL)
   1729 			errexit("registershadowclient: cannot malloc");
   1730 		sci->next = *info;
   1731 		*info = sci;
   1732 		sci->shadow = shadow;
   1733 		sci->totalClients = 0;
   1734 		sci->clients = newshadowclient(NULL);
   1735 	}
   1736 
   1737 	sci->totalClients++;
   1738 	scc = sci->clients;
   1739 	if (scc->nclients >= maxshadowclients) {
   1740 		scc = newshadowclient(sci->clients);
   1741 		sci->clients = scc;
   1742 	}
   1743 
   1744 	scc->client[scc->nclients++] = client;
   1745 }
   1746 
   1747 /*
   1748  * Locate and discard a shadow.
   1749  */
   1750 void
   1751 clearshadow(fsck_ino_t shadow, struct shadowclientinfo **info)
   1752 {
   1753 	struct shadowclientinfo *sci, *prev;
   1754 
   1755 	/*
   1756 	 * Do we have a record for this shadow?
   1757 	 */
   1758 	prev = NULL;
   1759 	for (sci = *info; sci != NULL; sci = sci->next) {
   1760 		if (sci->shadow == shadow)
   1761 			break;
   1762 		prev = sci;
   1763 	}
   1764 
   1765 	if (sci != NULL) {
   1766 		/*
   1767 		 * First, pull it off the list, since we know there
   1768 		 * shouldn't be any future references to this one.
   1769 		 */
   1770 		if (prev == NULL)
   1771 			*info = sci->next;
   1772 		else
   1773 			prev->next = sci->next;
   1774 		deshadow(sci, clearattrref);
   1775 	}
   1776 }
   1777 
   1778 /*
   1779  * Discard all memory used to track clients of a shadow.
   1780  */
   1781 void
   1782 deshadow(struct shadowclientinfo *sci, void (*cb)(fsck_ino_t))
   1783 {
   1784 	struct shadowclients *clients, *discard;
   1785 	int idx;
   1786 
   1787 	clients = sci->clients;
   1788 	while (clients != NULL) {
   1789 		discard = clients;
   1790 		clients = clients->next;
   1791 		if (discard->client != NULL) {
   1792 			if (cb != NULL) {
   1793 				for (idx = 0; idx < discard->nclients; idx++)
   1794 					(*cb)(discard->client[idx]);
   1795 			}
   1796 			free((void *)discard->client);
   1797 		}
   1798 		free((void *)discard);
   1799 	}
   1800 
   1801 	free((void *)sci);
   1802 }
   1803 
   1804 /*
   1805  * Allocate more buffer as need arises but allocate one at a time.
   1806  * This is done to make sure that fsck does not exit with error if it
   1807  * needs more buffer to complete its task.
   1808  */
   1809 static struct bufarea *
   1810 alloc_bufarea(void)
   1811 {
   1812 	struct bufarea *newbp;
   1813 	caddr_t bufp;
   1814 
   1815 	bufp = malloc((unsigned int)sblock.fs_bsize);
   1816 	if (bufp == NULL)
   1817 		return (NULL);
   1818 
   1819 	newbp = (struct bufarea *)malloc(sizeof (struct bufarea));
   1820 	if (newbp == NULL) {
   1821 		free((void *)bufp);
   1822 		return (NULL);
   1823 	}
   1824 
   1825 	initbarea(newbp);
   1826 	newbp->b_un.b_buf = bufp;
   1827 	newbp->b_prev = &bufhead;
   1828 	newbp->b_next = bufhead.b_next;
   1829 	bufhead.b_next->b_prev = newbp;
   1830 	bufhead.b_next = newbp;
   1831 	bufhead.b_size++;
   1832 	return (newbp);
   1833 }
   1834 
   1835 /*
   1836  * We length-limit in both unrawname() and rawname() to avoid
   1837  * overflowing our arrays or those of our naive, trusting callers.
   1838  */
   1839 
   1840 caddr_t
   1841 unrawname(caddr_t name)
   1842 {
   1843 	caddr_t dp;
   1844 	static char fullname[MAXPATHLEN + 1];
   1845 
   1846 	if ((dp = getfullblkname(name)) == NULL)
   1847 		return ("");
   1848 
   1849 	(void) strlcpy(fullname, dp, sizeof (fullname));
   1850 	/*
   1851 	 * Not reporting under debug, as the allocation isn't
   1852 	 * reported by getfullblkname.  The idea is that we
   1853 	 * produce balanced alloc/free instances.
   1854 	 */
   1855 	free(dp);
   1856 
   1857 	return (fullname);
   1858 }
   1859 
   1860 caddr_t
   1861 rawname(caddr_t name)
   1862 {
   1863 	caddr_t dp;
   1864 	static char fullname[MAXPATHLEN + 1];
   1865 
   1866 	if ((dp = getfullrawname(name)) == NULL)
   1867 		return ("");
   1868 
   1869 	(void) strlcpy(fullname, dp, sizeof (fullname));
   1870 	/*
   1871 	 * Not reporting under debug, as the allocation isn't
   1872 	 * reported by getfullblkname.  The idea is that we
   1873 	 * produce balanced alloc/free instances.
   1874 	 */
   1875 	free(dp);
   1876 
   1877 	return (fullname);
   1878 }
   1879 
   1880 /*
   1881  * Make sure that a cg header looks at least moderately reasonable.
   1882  * We want to be able to trust the contents enough to be able to use
   1883  * the standard accessor macros.  So, besides looking at the obvious
   1884  * such as the magic number, we verify that the offset field values
   1885  * are properly aligned and not too big or small.
   1886  *
   1887  * Returns a NULL pointer if the cg is sane enough for our needs, else
   1888  * a dynamically-allocated string describing all of its faults.
   1889  */
   1890 #define	Append_Error(full, full_len, addition, addition_len) \
   1891 	if (full == NULL) { \
   1892 		full = addition; \
   1893 		full_len = addition_len; \
   1894 	} else { \
   1895 		/* lint doesn't think realloc() understands NULLs */ \
   1896 		full = realloc(full, full_len + addition_len + 1); \
   1897 		if (full == NULL) { \
   1898 			errexit("Out of memory in cg_sanity"); \
   1899 			/* NOTREACHED */ \
   1900 		} \
   1901 		(void) strcpy(full + full_len, addition); \
   1902 		full_len += addition_len; \
   1903 		free(addition); \
   1904 	}
   1905 
   1906 caddr_t
   1907 cg_sanity(struct cg *cgp, int cgno)
   1908 {
   1909 	caddr_t full_err;
   1910 	caddr_t this_err = NULL;
   1911 	int full_len, this_len;
   1912 	daddr32_t ndblk;
   1913 	daddr32_t exp_btotoff, exp_boff, exp_iusedoff;
   1914 	daddr32_t exp_freeoff, exp_nextfreeoff;
   1915 
   1916 	cg_constants(cgno, &exp_btotoff, &exp_boff, &exp_iusedoff,
   1917 	    &exp_freeoff, &exp_nextfreeoff, &ndblk);
   1918 
   1919 	full_err = NULL;
   1920 	full_len = 0;
   1921 
   1922 	if (!cg_chkmagic(cgp)) {
   1923 		this_len = fsck_asprintf(&this_err,
   1924 		    "BAD CG MAGIC NUMBER (0x%x should be 0x%x)\n",
   1925 		    cgp->cg_magic, CG_MAGIC);
   1926 		Append_Error(full_err, full_len, this_err, this_len);
   1927 	}
   1928 
   1929 	if (cgp->cg_cgx != cgno) {
   1930 		this_len = fsck_asprintf(&this_err,
   1931 		    "WRONG CG NUMBER (%d should be %d)\n",
   1932 		    cgp->cg_cgx, cgno);
   1933 		Append_Error(full_err, full_len, this_err, this_len);
   1934 	}
   1935 
   1936 	if ((cgp->cg_btotoff & 3) != 0) {
   1937 		this_len = fsck_asprintf(&this_err,
   1938 		    "BLOCK TOTALS OFFSET %d NOT FOUR-BYTE ALIGNED\n",
   1939 		    cgp->cg_btotoff);
   1940 		Append_Error(full_err, full_len, this_err, this_len);
   1941 	}
   1942 
   1943 	if ((cgp->cg_boff & 1) != 0) {
   1944 		this_len = fsck_asprintf(&this_err,
   1945 	    "FREE BLOCK POSITIONS TABLE OFFSET %d NOT TWO-BYTE ALIGNED\n",
   1946 		    cgp->cg_boff);
   1947 		Append_Error(full_err, full_len, this_err, this_len);
   1948 	}
   1949 
   1950 	if ((cgp->cg_ncyl < 1) || (cgp->cg_ncyl > sblock.fs_cpg)) {
   1951 		if (cgp->cg_ncyl < 1) {
   1952 			this_len = fsck_asprintf(&this_err,
   1953 	    "IMPOSSIBLE NUMBER OF CYLINDERS IN GROUP (%d is less than 1)\n",
   1954 			    cgp->cg_ncyl);
   1955 		} else {
   1956 			this_len = fsck_asprintf(&this_err,
   1957 	    "IMPOSSIBLE NUMBER OF CYLINDERS IN GROUP (%d is greater than %d)\n",
   1958 			    cgp->cg_ncyl, sblock.fs_cpg);
   1959 		}
   1960 		Append_Error(full_err, full_len, this_err, this_len);
   1961 	}
   1962 
   1963 	if (cgp->cg_niblk != sblock.fs_ipg) {
   1964 		this_len = fsck_asprintf(&this_err,
   1965 		    "INCORRECT NUMBER OF INODES IN GROUP (%d should be %d)\n",
   1966 		    cgp->cg_niblk, sblock.fs_ipg);
   1967 		Append_Error(full_err, full_len, this_err, this_len);
   1968 	}
   1969 
   1970 	if (cgp->cg_ndblk != ndblk) {
   1971 		this_len = fsck_asprintf(&this_err,
   1972 	    "INCORRECT NUMBER OF DATA BLOCKS IN GROUP (%d should be %d)\n",
   1973 		    cgp->cg_ndblk, ndblk);
   1974 		Append_Error(full_err, full_len, this_err, this_len);
   1975 	}
   1976 
   1977 	if ((cgp->cg_rotor < 0) || (cgp->cg_rotor >= ndblk)) {
   1978 		this_len = fsck_asprintf(&this_err,
   1979 		    "IMPOSSIBLE BLOCK ALLOCATION ROTOR POSITION "
   1980 		    "(%d should be at least 0 and less than %d)\n",
   1981 		    cgp->cg_rotor, ndblk);
   1982 		Append_Error(full_err, full_len, this_err, this_len);
   1983 	}
   1984 
   1985 	if ((cgp->cg_frotor < 0) || (cgp->cg_frotor >= ndblk)) {
   1986 		this_len = fsck_asprintf(&this_err,
   1987 		    "IMPOSSIBLE FRAGMENT ALLOCATION ROTOR POSITION "
   1988 		    "(%d should be at least 0 and less than %d)\n",
   1989 		    cgp->cg_frotor, ndblk);
   1990 		Append_Error(full_err, full_len, this_err, this_len);
   1991 	}
   1992 
   1993 	if ((cgp->cg_irotor < 0) || (cgp->cg_irotor >= sblock.fs_ipg)) {
   1994 		this_len = fsck_asprintf(&this_err,
   1995 		    "IMPOSSIBLE INODE ALLOCATION ROTOR POSITION "
   1996 		    "(%d should be at least 0 and less than %d)\n",
   1997 		    cgp->cg_irotor, sblock.fs_ipg);
   1998 		Append_Error(full_err, full_len, this_err, this_len);
   1999 	}
   2000 
   2001 	if (cgp->cg_btotoff != exp_btotoff) {
   2002 		this_len = fsck_asprintf(&this_err,
   2003 		    "INCORRECT BLOCK TOTALS OFFSET (%d should be %d)\n",
   2004 		    cgp->cg_btotoff, exp_btotoff);
   2005 		Append_Error(full_err, full_len, this_err, this_len);
   2006 	}
   2007 
   2008 	if (cgp->cg_boff != exp_boff) {
   2009 		this_len = fsck_asprintf(&this_err,
   2010 		    "BAD FREE BLOCK POSITIONS TABLE OFFSET (%d should %d)\n",
   2011 		    cgp->cg_boff, exp_boff);
   2012 		Append_Error(full_err, full_len, this_err, this_len);
   2013 	}
   2014 
   2015 	if (cgp->cg_iusedoff != exp_iusedoff) {
   2016 		this_len = fsck_asprintf(&this_err,
   2017 		    "INCORRECT USED INODE MAP OFFSET (%d should be %d)\n",
   2018 		    cgp->cg_iusedoff, exp_iusedoff);
   2019 		Append_Error(full_err, full_len, this_err, this_len);
   2020 	}
   2021 
   2022 	if (cgp->cg_freeoff != exp_freeoff) {
   2023 		this_len = fsck_asprintf(&this_err,
   2024 		    "INCORRECT FREE FRAGMENT MAP OFFSET (%d should be %d)\n",
   2025 		    cgp->cg_freeoff, exp_freeoff);
   2026 		Append_Error(full_err, full_len, this_err, this_len);
   2027 	}
   2028 
   2029 	if (cgp->cg_nextfreeoff != exp_nextfreeoff) {
   2030 		this_len = fsck_asprintf(&this_err,
   2031 		    "END OF HEADER POSITION INCORRECT (%d should be %d)\n",
   2032 		    cgp->cg_nextfreeoff, exp_nextfreeoff);
   2033 		Append_Error(full_err, full_len, this_err, this_len);
   2034 	}
   2035 
   2036 	return (full_err);
   2037 }
   2038 
   2039 #undef	Append_Error
   2040 
   2041 /*
   2042  * This is taken from mkfs, and is what is used to come up with the
   2043  * original values for a struct cg.  This implies that, since these
   2044  * are all constants, recalculating them now should give us the same
   2045  * thing as what's on disk.
   2046  */
   2047 static void
   2048 cg_constants(int cgno, daddr32_t *btotoff, daddr32_t *boff,
   2049 	daddr32_t *iusedoff, daddr32_t *freeoff, daddr32_t *nextfreeoff,
   2050 	daddr32_t *ndblk)
   2051 {
   2052 	daddr32_t cbase, dmax;
   2053 	struct cg *cgp;
   2054 
   2055 	(void) getblk(&cgblk, (diskaddr_t)cgtod(&sblock, cgno),
   2056 	    (size_t)sblock.fs_cgsize);
   2057 	cgp = cgblk.b_un.b_cg;
   2058 
   2059 	cbase = cgbase(&sblock, cgno);
   2060 	dmax = cbase + sblock.fs_fpg;
   2061 	if (dmax > sblock.fs_size)
   2062 		dmax = sblock.fs_size;
   2063 
   2064 	/* LINTED pointer difference won't overflow */
   2065 	*btotoff = &cgp->cg_space[0] - (uchar_t *)(&cgp->cg_link);
   2066 	*boff = *btotoff + sblock.fs_cpg * sizeof (daddr32_t);
   2067 	*iusedoff = *boff + sblock.fs_cpg * sblock.fs_nrpos * sizeof (int16_t);
   2068 	*freeoff = *iusedoff + howmany(sblock.fs_ipg, NBBY);
   2069 	*nextfreeoff = *freeoff +
   2070 	    howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY);
   2071 	*ndblk = dmax - cbase;
   2072 }
   2073 
   2074 /*
   2075  * Corrects all fields in the cg that can be done with the available
   2076  * redundant data.
   2077  */
   2078 void
   2079 fix_cg(struct cg *cgp, int cgno)
   2080 {
   2081 	daddr32_t exp_btotoff, exp_boff, exp_iusedoff;
   2082 	daddr32_t exp_freeoff, exp_nextfreeoff;
   2083 	daddr32_t ndblk;
   2084 
   2085 	cg_constants(cgno, &exp_btotoff, &exp_boff, &exp_iusedoff,
   2086 	    &exp_freeoff, &exp_nextfreeoff, &ndblk);
   2087 
   2088 	if (cgp->cg_cgx != cgno) {
   2089 		cgp->cg_cgx = cgno;
   2090 	}
   2091 
   2092 	if ((cgp->cg_ncyl < 1) || (cgp->cg_ncyl > sblock.fs_cpg)) {
   2093 		if (cgno == (sblock.fs_ncg - 1)) {
   2094 			cgp->cg_ncyl = sblock.fs_ncyl -
   2095 			    (sblock.fs_cpg * cgno);
   2096 		} else {
   2097 			cgp->cg_ncyl = sblock.fs_cpg;
   2098 		}
   2099 	}
   2100 
   2101 	if (cgp->cg_niblk != sblock.fs_ipg) {
   2102 		/*
   2103 		 * This is not used by the kernel, so it's pretty
   2104 		 * harmless if it's wrong.
   2105 		 */
   2106 		cgp->cg_niblk = sblock.fs_ipg;
   2107 	}
   2108 
   2109 	if (cgp->cg_ndblk != ndblk) {
   2110 		cgp->cg_ndblk = ndblk;
   2111 	}
   2112 
   2113 	/*
   2114 	 * For the rotors, any position's valid, so pick the one we know
   2115 	 * will always exist.
   2116 	 */
   2117 	if ((cgp->cg_rotor < 0) || (cgp->cg_rotor >= cgp->cg_ndblk)) {
   2118 		cgp->cg_rotor = 0;
   2119 	}
   2120 
   2121 	if ((cgp->cg_frotor < 0) || (cgp->cg_frotor >= cgp->cg_ndblk)) {
   2122 		cgp->cg_frotor = 0;
   2123 	}
   2124 
   2125 	if ((cgp->cg_irotor < 0) || (cgp->cg_irotor >= sblock.fs_ipg)) {
   2126 		cgp->cg_irotor = 0;
   2127 	}
   2128 
   2129 	/*
   2130 	 * For btotoff and boff, if they're misaligned they won't
   2131 	 * match the expected values, so we're catching both cases
   2132 	 * here.  Of course, if any of these are off, it seems likely
   2133 	 * that the tables really won't be where we calculate they
   2134 	 * should be anyway.
   2135 	 */
   2136 	if (cgp->cg_btotoff != exp_btotoff) {
   2137 		cgp->cg_btotoff = exp_btotoff;
   2138 	}
   2139 
   2140 	if (cgp->cg_boff != exp_boff) {
   2141 		cgp->cg_boff = exp_boff;
   2142 	}
   2143 
   2144 	if (cgp->cg_iusedoff != exp_iusedoff) {
   2145 		cgp->cg_iusedoff = exp_iusedoff;
   2146 	}
   2147 
   2148 	if (cgp->cg_freeoff != exp_freeoff) {
   2149 		cgp->cg_freeoff = exp_freeoff;
   2150 	}
   2151 
   2152 	if (cgp->cg_nextfreeoff != exp_nextfreeoff) {
   2153 		cgp->cg_nextfreeoff = exp_nextfreeoff;
   2154 	}
   2155 
   2156 	/*
   2157 	 * Reset the magic, as we've recreated this cg, also
   2158 	 * update the cg_time, as we're writing out the cg
   2159 	 */
   2160 	cgp->cg_magic = CG_MAGIC;
   2161 	cgp->cg_time = time(NULL);
   2162 
   2163 	/*
   2164 	 * We know there was at least one correctable problem,
   2165 	 * or else we wouldn't have been called.  So instead of
   2166 	 * marking the buffer dirty N times above, just do it
   2167 	 * once here.
   2168 	 */
   2169 	cgdirty();
   2170 }
   2171 
   2172 void
   2173 examinelog(void (*cb)(daddr32_t))
   2174 {
   2175 	struct bufarea *bp;
   2176 	extent_block_t *ebp;
   2177 	extent_t *ep;
   2178 	daddr32_t nfno, fno;
   2179 	int i;
   2180 	int j;
   2181 
   2182 	/*
   2183 	 * Since ufs stores fs_logbno as blocks and MTBufs stores it as frags
   2184 	 * we need to translate accordingly using logbtodb()
   2185 	 */
   2186 
   2187 	if (logbtodb(&sblock, sblock.fs_logbno) < SBLOCK) {
   2188 		if (debug) {
   2189 			(void) printf("fs_logbno < SBLOCK: %ld < %ld\n" \
   2190 			    "Aborting log examination\n", \
   2191 			    logbtodb(&sblock, sblock.fs_logbno), SBLOCK);
   2192 		}
   2193 		return;
   2194 	}
   2195 
   2196 	/*
   2197 	 * Read errors will return zeros, which will cause us
   2198 	 * to do nothing harmful, so don't need to handle it.
   2199 	 */
   2200 	bp = getdatablk(logbtofrag(&sblock, sblock.fs_logbno),
   2201 	    (size_t)sblock.fs_bsize);
   2202 	ebp = (void *)bp->b_un.b_buf;
   2203 
   2204 	/*
   2205 	 * Does it look like a log allocation table?
   2206 	 */
   2207 	/* LINTED pointer cast is aligned */
   2208 	if (!log_checksum(&ebp->chksum, (int32_t *)bp->b_un.b_buf,
   2209 	    sblock.fs_bsize))
   2210 		return;
   2211 	if (ebp->type != LUFS_EXTENTS || ebp->nextents == 0)
   2212 		return;
   2213 
   2214 	ep = &ebp->extents[0];
   2215 	for (i = 0; i < ebp->nextents; ++i, ++ep) {
   2216 		fno = logbtofrag(&sblock, ep->pbno);
   2217 		nfno = dbtofsb(&sblock, ep->nbno);
   2218 		for (j = 0; j < nfno; ++j, ++fno) {
   2219 			/*
   2220 			 * Invoke the callback first, so that pass1 can
   2221 			 * mark the log blocks in-use.  Then, if any
   2222 			 * subsequent pass over the log shows us that a
   2223 			 * block got freed (say, it was also claimed by
   2224 			 * an inode that we cleared), we can safely declare
   2225 			 * the log bad.
   2226 			 */
   2227 			if (cb != NULL)
   2228 				(*cb)(fno);
   2229 			if (!testbmap(fno))
   2230 				islogok = 0;
   2231 		}
   2232 	}
   2233 	brelse(bp);
   2234 
   2235 	if (cb != NULL) {
   2236 		fno = logbtofrag(&sblock, sblock.fs_logbno);
   2237 		for (j = 0; j < sblock.fs_frag; ++j, ++fno)
   2238 			(*cb)(fno);
   2239 	}
   2240 }
   2241 
   2242 static void
   2243 freelogblk(daddr32_t frag)
   2244 {
   2245 	freeblk(sblock.fs_logbno, frag, 1);
   2246 }
   2247 
   2248 caddr_t
   2249 file_id(fsck_ino_t inum, mode_t mode)
   2250 {
   2251 	static char name[MAXPATHLEN + 1];
   2252 
   2253 	if (lfdir == inum) {
   2254 		return (lfname);
   2255 	}
   2256 
   2257 	if ((mode & IFMT) == IFDIR) {
   2258 		(void) strcpy(name, "DIR");
   2259 	} else if ((mode & IFMT) == IFATTRDIR) {
   2260 		(void) strcpy(name, "ATTR DIR");
   2261 	} else if ((mode & IFMT) == IFSHAD) {
   2262 		(void) strcpy(name, "ACL");
   2263 	} else {
   2264 		(void) strcpy(name, "FILE");
   2265 	}
   2266 
   2267 	return (name);
   2268 }
   2269 
   2270 /*
   2271  * Simple initializer for inodesc structures, so users of only a few
   2272  * fields don't have to worry about getting the right defaults for
   2273  * everything out.
   2274  */
   2275 void
   2276 init_inodesc(struct inodesc *idesc)
   2277 {
   2278 	/*
   2279 	 * Most fields should be zero, just hit the special cases.
   2280 	 */
   2281 	(void) memset((void *)idesc, 0, sizeof (struct inodesc));
   2282 	idesc->id_fix = DONTKNOW;
   2283 	idesc->id_lbn = -1;
   2284 	idesc->id_truncto = -1;
   2285 	idesc->id_firsthole = -1;
   2286 }
   2287 
   2288 /*
   2289  * Compare routine for tsearch(C) to use on ino_t instances.
   2290  */
   2291 int
   2292 ino_t_cmp(const void *left, const void *right)
   2293 {
   2294 	const fsck_ino_t lino = (const fsck_ino_t)left;
   2295 	const fsck_ino_t rino = (const fsck_ino_t)right;
   2296 
   2297 	return (lino - rino);
   2298 }
   2299 
   2300 int
   2301 cgisdirty(void)
   2302 {
   2303 	return (cgblk.b_dirty);
   2304 }
   2305 
   2306 void
   2307 cgflush(void)
   2308 {
   2309 	flush(fswritefd, &cgblk);
   2310 }
   2311 
   2312 void
   2313 dirty(struct bufarea *bp)
   2314 {
   2315 	if (fswritefd < 0) {
   2316 		/*
   2317 		 * No one should call dirty() in read only mode.
   2318 		 * But if one does, it's not fatal issue. Just warn him.
   2319 		 */
   2320 		pwarn("WON'T SET DIRTY FLAG IN READ_ONLY MODE\n");
   2321 	} else {
   2322 		(bp)->b_dirty = 1;
   2323 		isdirty = 1;
   2324 	}
   2325 }
   2326 
   2327 void
   2328 initbarea(struct bufarea *bp)
   2329 {
   2330 	(bp)->b_dirty = 0;
   2331 	(bp)->b_bno = (diskaddr_t)-1LL;
   2332 	(bp)->b_flags = 0;
   2333 	(bp)->b_cnt = 0;
   2334 	(bp)->b_errs = 0;
   2335 }
   2336 
   2337 /*
   2338  * Partition-sizing routines adapted from ../newfs/newfs.c.
   2339  * Needed because calcsb() needs to use mkfs to work out what the
   2340  * superblock should be, and mkfs insists on being told how many
   2341  * sectors to use.
   2342  *
   2343  * Error handling assumes we're never called while preening.
   2344  *
   2345  * XXX This should be extracted into a ../ufslib.{c,h},
   2346  *     in the same spirit to ../../fslib.{c,h}.  Once that is
   2347  *     done, both fsck and newfs should be modified to link
   2348  *     against it.
   2349  */
   2350 
   2351 static int label_type;
   2352 
   2353 #define	LABEL_TYPE_VTOC		1
   2354 #define	LABEL_TYPE_EFI		2
   2355 #define	LABEL_TYPE_OTHER	3
   2356 
   2357 #define	MB			(1024 * 1024)
   2358 #define	SECTORS_PER_TERABYTE	(1LL << 31)
   2359 #define	FS_SIZE_UPPER_LIMIT	0x100000000000LL
   2360 
   2361 diskaddr_t
   2362 getdisksize(caddr_t disk, int fd)
   2363 {
   2364 	int rpm;
   2365 	struct dk_geom g;
   2366 	struct dk_cinfo ci;
   2367 	diskaddr_t actual_size;
   2368 
   2369 	/*
   2370 	 * get_device_size() determines the actual size of the
   2371 	 * device, and also the disk's attributes, such as geometry.
   2372 	 */
   2373 	actual_size = get_device_size(fd, disk);
   2374 
   2375 	if (label_type == LABEL_TYPE_VTOC) {
   2376 		if (ioctl(fd, DKIOCGGEOM, &g)) {
   2377 			pwarn("%s: Unable to read Disk geometry", disk);
   2378 			return (0);
   2379 		}
   2380 		if (sblock.fs_nsect == 0)
   2381 			sblock.fs_nsect = g.dkg_nsect;
   2382 		if (sblock.fs_ntrak == 0)
   2383 			sblock.fs_ntrak = g.dkg_nhead;
   2384 		if (sblock.fs_rps == 0) {
   2385 			rpm = ((int)g.dkg_rpm <= 0) ? 3600: g.dkg_rpm;
   2386 			sblock.fs_rps = rpm / 60;
   2387 		}
   2388 	}
   2389 
   2390 	if (sblock.fs_bsize == 0)
   2391 		sblock.fs_bsize = MAXBSIZE;
   2392 
   2393 	/*
   2394 	 * Adjust maxcontig by the device's maxtransfer. If maxtransfer
   2395 	 * information is not available, default to the min of a MB and
   2396 	 * maxphys.
   2397 	 */
   2398 	if (sblock.fs_maxcontig == -1 && ioctl(fd, DKIOCINFO, &ci) == 0) {
   2399 		sblock.fs_maxcontig = ci.dki_maxtransfer * DEV_BSIZE;
   2400 		if (sblock.fs_maxcontig < 0) {
   2401 			int gotit, maxphys;
   2402 
   2403 			gotit = fsgetmaxphys(&maxphys, NULL);
   2404 
   2405 			/*
   2406 			 * If we cannot get the maxphys value, default
   2407 			 * to ufs_maxmaxphys (MB).
   2408 			 */
   2409 			if (gotit) {
   2410 				sblock.fs_maxcontig = MIN(maxphys, MB);
   2411 			} else {
   2412 				sblock.fs_maxcontig = MB;
   2413 			}
   2414 		}
   2415 		sblock.fs_maxcontig /= sblock.fs_bsize;
   2416 	}
   2417 
   2418 	return (actual_size);
   2419 }
   2420 
   2421 /*
   2422  * Figure out how big the partition we're dealing with is.
   2423  */
   2424 static diskaddr_t
   2425 get_device_size(int fd, caddr_t name)
   2426 {
   2427 	struct extvtoc vtoc;
   2428 	struct dk_gpt *efi_vtoc;
   2429 	diskaddr_t slicesize = 0;
   2430 
   2431 	int index = read_extvtoc(fd, &vtoc);
   2432 
   2433 	if (index >= 0) {
   2434 		label_type = LABEL_TYPE_VTOC;
   2435 	} else {
   2436 		if (index == VT_ENOTSUP || index == VT_ERROR) {
   2437 			/* it might be an EFI label */
   2438 			index = efi_alloc_and_read(fd, &efi_vtoc);
   2439 			if (index >= 0)
   2440 				label_type = LABEL_TYPE_EFI;
   2441 		}
   2442 	}
   2443 
   2444 	if (index < 0) {
   2445 		/*
   2446 		 * Since both attempts to read the label failed, we're
   2447 		 * going to fall back to a brute force approach to
   2448 		 * determining the device's size:  see how far out we can
   2449 		 * perform reads on the device.
   2450 		 */
   2451 
   2452 		slicesize = brute_force_get_device_size(fd);
   2453 		if (slicesize == 0) {
   2454 			switch (index) {
   2455 			case VT_ERROR:
   2456 				pwarn("%s: %s\n", name, strerror(errno));
   2457 				break;
   2458 			case VT_EIO:
   2459 				pwarn("%s: I/O error accessing VTOC", name);
   2460 				break;
   2461 			case VT_EINVAL:
   2462 				pwarn("%s: Invalid field in VTOC", name);
   2463 				break;
   2464 			default:
   2465 				pwarn("%s: unknown error %d accessing VTOC",
   2466 				    name, index);
   2467 				break;
   2468 			}
   2469 			return (0);
   2470 		} else {
   2471 			label_type = LABEL_TYPE_OTHER;
   2472 		}
   2473 	}
   2474 
   2475 	if (label_type == LABEL_TYPE_EFI) {
   2476 		slicesize = efi_vtoc->efi_parts[index].p_size;
   2477 		efi_free(efi_vtoc);
   2478 	} else if (label_type == LABEL_TYPE_VTOC) {
   2479 		slicesize = vtoc.v_part[index].p_size;
   2480 	}
   2481 
   2482 	return (slicesize);
   2483 }
   2484 
   2485 /*
   2486  * brute_force_get_device_size
   2487  *
   2488  * Determine the size of the device by seeing how far we can
   2489  * read.  Doing an llseek( , , SEEK_END) would probably work
   2490  * in most cases, but we've seen at least one third-party driver
   2491  * which doesn't correctly support the SEEK_END option when the
   2492  * the device is greater than a terabyte.
   2493  */
   2494 
   2495 static diskaddr_t
   2496 brute_force_get_device_size(int fd)
   2497 {
   2498 	diskaddr_t	min_fail = 0;
   2499 	diskaddr_t	max_succeed = 0;
   2500 	diskaddr_t	cur_db_off;
   2501 	char 		buf[DEV_BSIZE];
   2502 
   2503 	/*
   2504 	 * First, see if we can read the device at all, just to
   2505 	 * eliminate errors that have nothing to do with the
   2506 	 * device's size.
   2507 	 */
   2508 
   2509 	if (((llseek(fd, (offset_t)0, SEEK_SET)) == -1) ||
   2510 	    ((read(fd, buf, DEV_BSIZE)) == -1))
   2511 		return (0);  /* can't determine size */
   2512 
   2513 	/*
   2514 	 * Now, go sequentially through the multiples of 4TB
   2515 	 * to find the first read that fails (this isn't strictly
   2516 	 * the most efficient way to find the actual size if the
   2517 	 * size really could be anything between 0 and 2**64 bytes.
   2518 	 * We expect the sizes to be less than 16 TB for some time,
   2519 	 * so why do a bunch of reads that are larger than that?
   2520 	 * However, this algorithm *will* work for sizes of greater
   2521 	 * than 16 TB.  We're just not optimizing for those sizes.)
   2522 	 */
   2523 
   2524 	/*
   2525 	 * XXX lint uses 32-bit arithmetic for doing flow analysis.
   2526 	 * We're using > 32-bit constants here.  Therefore, its flow
   2527 	 * analysis is wrong.  For the time being, ignore complaints
   2528 	 * from it about the body of the for() being unreached.
   2529 	 */
   2530 	for (cur_db_off = SECTORS_PER_TERABYTE * 4;
   2531 	    (min_fail == 0) && (cur_db_off < FS_SIZE_UPPER_LIMIT);
   2532 	    cur_db_off += 4 * SECTORS_PER_TERABYTE) {
   2533 		if ((llseek(fd, (offset_t)(cur_db_off * DEV_BSIZE),
   2534 		    SEEK_SET) == -1) ||
   2535 		    (read(fd, buf, DEV_BSIZE) != DEV_BSIZE))
   2536 			min_fail = cur_db_off;
   2537 		else
   2538 			max_succeed = cur_db_off;
   2539 	}
   2540 
   2541 	/*
   2542 	 * XXX Same lint flow analysis problem as above.
   2543 	 */
   2544 	if (min_fail == 0)
   2545 		return (0);
   2546 
   2547 	/*
   2548 	 * We now know that the size of the device is less than
   2549 	 * min_fail and greater than or equal to max_succeed.  Now
   2550 	 * keep splitting the difference until the actual size in
   2551 	 * sectors in known.  We also know that the difference
   2552 	 * between max_succeed and min_fail at this time is
   2553 	 * 4 * SECTORS_PER_TERABYTE, which is a power of two, which
   2554 	 * simplifies the math below.
   2555 	 */
   2556 
   2557 	while (min_fail - max_succeed > 1) {
   2558 		cur_db_off = max_succeed + (min_fail - max_succeed)/2;
   2559 		if (((llseek(fd, (offset_t)(cur_db_off * DEV_BSIZE),
   2560 		    SEEK_SET)) == -1) ||
   2561 		    ((read(fd, buf, DEV_BSIZE)) != DEV_BSIZE))
   2562 			min_fail = cur_db_off;
   2563 		else
   2564 			max_succeed = cur_db_off;
   2565 	}
   2566 
   2567 	/* the size is the last successfully read sector offset plus one */
   2568 	return (max_succeed + 1);
   2569 }
   2570 
   2571 static void
   2572 vfileerror(fsck_ino_t cwd, fsck_ino_t ino, caddr_t fmt, va_list ap)
   2573 {
   2574 	struct dinode *dp;
   2575 	char pathbuf[MAXPATHLEN + 1];
   2576 
   2577 	vpwarn(fmt, ap);
   2578 	(void) putchar(' ');
   2579 	pinode(ino);
   2580 	(void) printf("\n");
   2581 	getpathname(pathbuf, cwd, ino);
   2582 	if (ino < UFSROOTINO || ino > maxino) {
   2583 		pfatal("NAME=%s\n", pathbuf);
   2584 		return;
   2585 	}
   2586 	dp = ginode(ino);
   2587 	if (ftypeok(dp))
   2588 		pfatal("%s=%s\n", file_id(ino, dp->di_mode), pathbuf);
   2589 	else
   2590 		pfatal("NAME=%s\n", pathbuf);
   2591 }
   2592 
   2593 void
   2594 direrror(fsck_ino_t ino, caddr_t fmt, ...)
   2595 {
   2596 	va_list ap;
   2597 
   2598 	va_start(ap, fmt);
   2599 	vfileerror(ino, ino, fmt, ap);
   2600 	va_end(ap);
   2601 }
   2602 
   2603 static void
   2604 vdirerror(fsck_ino_t ino, caddr_t fmt, va_list ap)
   2605 {
   2606 	vfileerror(ino, ino, fmt, ap);
   2607 }
   2608 
   2609 void
   2610 fileerror(fsck_ino_t cwd, fsck_ino_t ino, caddr_t fmt, ...)
   2611 {
   2612 	va_list ap;
   2613 
   2614 	va_start(ap, fmt);
   2615 	vfileerror(cwd, ino, fmt, ap);
   2616 	va_end(ap);
   2617 }
   2618 
   2619 /*
   2620  * Adds the given inode to the orphaned-directories list, limbo_dirs.
   2621  * Assumes that the caller has set INCLEAR in the inode's statemap[]
   2622  * entry.
   2623  *
   2624  * With INCLEAR set, the inode will get ignored by passes 2 and 3,
   2625  * meaning it's effectively an orphan.  It needs to be noted now, so
   2626  * it will be remembered in pass 4.
   2627  */
   2628 
   2629 void
   2630 add_orphan_dir(fsck_ino_t ino)
   2631 {
   2632 	if (tsearch((void *)ino, &limbo_dirs, ino_t_cmp) == NULL)
   2633 		errexit("add_orphan_dir: out of memory");
   2634 }
   2635 
   2636 /*
   2637  * Remove an inode from the orphaned-directories list, presumably
   2638  * because it's been cleared.
   2639  */
   2640 void
   2641 remove_orphan_dir(fsck_ino_t ino)
   2642 {
   2643 	(void) tdelete((void *)ino, &limbo_dirs, ino_t_cmp);
   2644 }
   2645 
   2646 /*
   2647  * log_setsum() and log_checksum() are equivalent to lufs.c:setsum()
   2648  * and lufs.c:checksum().
   2649  */
   2650 static void
   2651 log_setsum(int32_t *sp, int32_t *lp, int nb)
   2652 {
   2653 	int32_t csum = 0;
   2654 
   2655 	*sp = 0;
   2656 	nb /= sizeof (int32_t);
   2657 	while (nb--)
   2658 		csum += *lp++;
   2659 	*sp = csum;
   2660 }
   2661 
   2662 static int
   2663 log_checksum(int32_t *sp, int32_t *lp, int nb)
   2664 {
   2665 	int32_t ssum = *sp;
   2666 
   2667 	log_setsum(sp, lp, nb);
   2668 	if (ssum != *sp) {
   2669 		*sp = ssum;
   2670 		return (0);
   2671 	}
   2672 	return (1);
   2673 }
   2674