xref: /titanic_41/usr/src/cmd/fs.d/ufs/fsck/utilities.c (revision ac88567a7a5bb7f01cf22cf366bc9d6203e24d7a)
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