xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/utilities.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
8*7c478bd9Sstevel@tonic-gate 
9*7c478bd9Sstevel@tonic-gate /*
10*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11*7c478bd9Sstevel@tonic-gate  * All rights reserved.
12*7c478bd9Sstevel@tonic-gate  *
13*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
14*7c478bd9Sstevel@tonic-gate  * provided that: (1) source distributions retain this entire copyright
15*7c478bd9Sstevel@tonic-gate  * notice and comment, and (2) distributions including binaries display
16*7c478bd9Sstevel@tonic-gate  * the following acknowledgement:  ``This product includes software
17*7c478bd9Sstevel@tonic-gate  * developed by the University of California, Berkeley and its contributors''
18*7c478bd9Sstevel@tonic-gate  * in the documentation or other materials provided with the distribution
19*7c478bd9Sstevel@tonic-gate  * and in all advertising materials mentioning features or use of this
20*7c478bd9Sstevel@tonic-gate  * software. Neither the name of the University nor the names of its
21*7c478bd9Sstevel@tonic-gate  * contributors may be used to endorse or promote products derived
22*7c478bd9Sstevel@tonic-gate  * from this software without specific prior written permission.
23*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25*7c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26*7c478bd9Sstevel@tonic-gate  */
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #include <stdio.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/filio.h>
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate #define	bcopy(f, t, n)    memcpy(t, f, n)
37*7c478bd9Sstevel@tonic-gate #define	bzero(s, n)	memset(s, 0, n)
38*7c478bd9Sstevel@tonic-gate #define	bcmp(s, d, n)	memcmp(s, d, n)
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #define	index(s, r)	strchr(s, r)
41*7c478bd9Sstevel@tonic-gate #define	rindex(s, r)	strrchr(s, r)
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_acl.h>
47*7c478bd9Sstevel@tonic-gate #define	_KERNEL
48*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h>
49*7c478bd9Sstevel@tonic-gate #undef _KERNEL
50*7c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/signal.h>
54*7c478bd9Sstevel@tonic-gate #include <string.h>
55*7c478bd9Sstevel@tonic-gate #include <ctype.h>
56*7c478bd9Sstevel@tonic-gate #include "fsck.h"
57*7c478bd9Sstevel@tonic-gate #include <sys/vfstab.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/lockfs.h>
59*7c478bd9Sstevel@tonic-gate #include <errno.h>
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate int64_t	diskreads, totalreads;	/* Disk cache statistics */
62*7c478bd9Sstevel@tonic-gate offset_t	llseek();
63*7c478bd9Sstevel@tonic-gate char	*malloc();
64*7c478bd9Sstevel@tonic-gate char	*mount_point = NULL;
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate extern int	mflag;
67*7c478bd9Sstevel@tonic-gate extern uint_t largefile_count;
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate static struct bufarea *alloc_bufarea();
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate ftypeok(dp)
72*7c478bd9Sstevel@tonic-gate 	struct dinode *dp;
73*7c478bd9Sstevel@tonic-gate {
74*7c478bd9Sstevel@tonic-gate 	switch (dp->di_mode & IFMT) {
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	case IFDIR:
77*7c478bd9Sstevel@tonic-gate 	case IFREG:
78*7c478bd9Sstevel@tonic-gate 	case IFBLK:
79*7c478bd9Sstevel@tonic-gate 	case IFCHR:
80*7c478bd9Sstevel@tonic-gate 	case IFLNK:
81*7c478bd9Sstevel@tonic-gate 	case IFSOCK:
82*7c478bd9Sstevel@tonic-gate 	case IFIFO:
83*7c478bd9Sstevel@tonic-gate 	case IFSHAD:
84*7c478bd9Sstevel@tonic-gate 	case IFATTRDIR:
85*7c478bd9Sstevel@tonic-gate 		return (1);
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	default:
88*7c478bd9Sstevel@tonic-gate 		if (debug)
89*7c478bd9Sstevel@tonic-gate 			printf("bad file type 0%o\n", dp->di_mode);
90*7c478bd9Sstevel@tonic-gate 		return (0);
91*7c478bd9Sstevel@tonic-gate 	}
92*7c478bd9Sstevel@tonic-gate }
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate acltypeok(dp)
95*7c478bd9Sstevel@tonic-gate 	struct dinode *dp;
96*7c478bd9Sstevel@tonic-gate {
97*7c478bd9Sstevel@tonic-gate 	if (CHECK_ACL_ALLOWED(dp->di_mode & IFMT))
98*7c478bd9Sstevel@tonic-gate 		return (1);
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	if (debug)
101*7c478bd9Sstevel@tonic-gate 		printf("bad file type for acl 0%o\n", dp->di_mode);
102*7c478bd9Sstevel@tonic-gate 	return (0);
103*7c478bd9Sstevel@tonic-gate }
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate reply(question)
106*7c478bd9Sstevel@tonic-gate 	char *question;
107*7c478bd9Sstevel@tonic-gate {
108*7c478bd9Sstevel@tonic-gate 	char line[80];
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	if (preen)
111*7c478bd9Sstevel@tonic-gate 		pfatal("INTERNAL ERROR: GOT TO reply()");
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	if (mflag) {
114*7c478bd9Sstevel@tonic-gate 		printf("\n");
115*7c478bd9Sstevel@tonic-gate 		printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
116*7c478bd9Sstevel@tonic-gate 			devname);
117*7c478bd9Sstevel@tonic-gate 		exit(39);
118*7c478bd9Sstevel@tonic-gate 	}
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	printf("\n%s? ", question);
121*7c478bd9Sstevel@tonic-gate 	if (nflag || fswritefd < 0) {
122*7c478bd9Sstevel@tonic-gate 		printf(" no\n\n");
123*7c478bd9Sstevel@tonic-gate 		iscorrupt = 1;		/* known to be corrupt */
124*7c478bd9Sstevel@tonic-gate 		return (0);
125*7c478bd9Sstevel@tonic-gate 	}
126*7c478bd9Sstevel@tonic-gate 	if (yflag) {
127*7c478bd9Sstevel@tonic-gate 		printf(" yes\n\n");
128*7c478bd9Sstevel@tonic-gate 		return (1);
129*7c478bd9Sstevel@tonic-gate 	}
130*7c478bd9Sstevel@tonic-gate 	if (getline(stdin, line, sizeof (line)) == EOF)
131*7c478bd9Sstevel@tonic-gate 		errexit("\n");
132*7c478bd9Sstevel@tonic-gate 	printf("\n");
133*7c478bd9Sstevel@tonic-gate 	if (line[0] == 'y' || line[0] == 'Y')
134*7c478bd9Sstevel@tonic-gate 		return (1);
135*7c478bd9Sstevel@tonic-gate 	else {
136*7c478bd9Sstevel@tonic-gate 		iscorrupt = 1;		/* known to be corrupt */
137*7c478bd9Sstevel@tonic-gate 		return (0);
138*7c478bd9Sstevel@tonic-gate 	}
139*7c478bd9Sstevel@tonic-gate }
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate getline(fp, loc, maxlen)
142*7c478bd9Sstevel@tonic-gate 	FILE *fp;
143*7c478bd9Sstevel@tonic-gate 	char *loc;
144*7c478bd9Sstevel@tonic-gate {
145*7c478bd9Sstevel@tonic-gate 	int n;
146*7c478bd9Sstevel@tonic-gate 	char *p, *lastloc;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	p = loc;
149*7c478bd9Sstevel@tonic-gate 	lastloc = &p[maxlen-1];
150*7c478bd9Sstevel@tonic-gate 	while ((n = getc(fp)) != '\n') {
151*7c478bd9Sstevel@tonic-gate 		if (n == EOF)
152*7c478bd9Sstevel@tonic-gate 			return (EOF);
153*7c478bd9Sstevel@tonic-gate 		if (!isspace(n) && p < lastloc)
154*7c478bd9Sstevel@tonic-gate 			*p++ = n;
155*7c478bd9Sstevel@tonic-gate 	}
156*7c478bd9Sstevel@tonic-gate 	*p = 0;
157*7c478bd9Sstevel@tonic-gate 	return (p - loc);
158*7c478bd9Sstevel@tonic-gate }
159*7c478bd9Sstevel@tonic-gate /*
160*7c478bd9Sstevel@tonic-gate  * Malloc buffers and set up cache.
161*7c478bd9Sstevel@tonic-gate  */
162*7c478bd9Sstevel@tonic-gate bufinit()
163*7c478bd9Sstevel@tonic-gate {
164*7c478bd9Sstevel@tonic-gate 	struct bufarea *bp;
165*7c478bd9Sstevel@tonic-gate 	int bufcnt, i;
166*7c478bd9Sstevel@tonic-gate 	char *bufp;
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	bufp = malloc((unsigned int)sblock.fs_bsize);
169*7c478bd9Sstevel@tonic-gate 	if (bufp == 0)
170*7c478bd9Sstevel@tonic-gate 		errexit("cannot allocate buffer pool\n");
171*7c478bd9Sstevel@tonic-gate 	cgblk.b_un.b_buf = bufp;
172*7c478bd9Sstevel@tonic-gate 	initbarea(&cgblk);
173*7c478bd9Sstevel@tonic-gate 	bufhead.b_next = bufhead.b_prev = &bufhead;
174*7c478bd9Sstevel@tonic-gate 	bufcnt = MAXBUFSPACE / sblock.fs_bsize;
175*7c478bd9Sstevel@tonic-gate 	if (bufcnt < MINBUFS)
176*7c478bd9Sstevel@tonic-gate 		bufcnt = MINBUFS;
177*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < bufcnt; i++) {
178*7c478bd9Sstevel@tonic-gate 		bp = (struct bufarea *)malloc(sizeof (struct bufarea));
179*7c478bd9Sstevel@tonic-gate 		bufp = malloc((unsigned int)sblock.fs_bsize);
180*7c478bd9Sstevel@tonic-gate 		if (bp == NULL || bufp == NULL) {
181*7c478bd9Sstevel@tonic-gate 			if (bp)
182*7c478bd9Sstevel@tonic-gate 				free((char *)bp);
183*7c478bd9Sstevel@tonic-gate 			if (bufp)
184*7c478bd9Sstevel@tonic-gate 				free(bufp);
185*7c478bd9Sstevel@tonic-gate 			if (i >= MINBUFS)
186*7c478bd9Sstevel@tonic-gate 				break;
187*7c478bd9Sstevel@tonic-gate 			errexit("cannot allocate buffer pool\n");
188*7c478bd9Sstevel@tonic-gate 		}
189*7c478bd9Sstevel@tonic-gate 		bp->b_un.b_buf = bufp;
190*7c478bd9Sstevel@tonic-gate 		bp->b_prev = &bufhead;
191*7c478bd9Sstevel@tonic-gate 		bp->b_next = bufhead.b_next;
192*7c478bd9Sstevel@tonic-gate 		bufhead.b_next->b_prev = bp;
193*7c478bd9Sstevel@tonic-gate 		bufhead.b_next = bp;
194*7c478bd9Sstevel@tonic-gate 		initbarea(bp);
195*7c478bd9Sstevel@tonic-gate 	}
196*7c478bd9Sstevel@tonic-gate 	bufhead.b_size = i;	/* save number of buffers */
197*7c478bd9Sstevel@tonic-gate 	pbp = pdirbp = NULL;
198*7c478bd9Sstevel@tonic-gate }
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate /*
201*7c478bd9Sstevel@tonic-gate  * Manage a cache of directory blocks.
202*7c478bd9Sstevel@tonic-gate  */
203*7c478bd9Sstevel@tonic-gate struct bufarea *
204*7c478bd9Sstevel@tonic-gate getdatablk(blkno, size)
205*7c478bd9Sstevel@tonic-gate 	daddr32_t blkno;
206*7c478bd9Sstevel@tonic-gate 	int size;
207*7c478bd9Sstevel@tonic-gate {
208*7c478bd9Sstevel@tonic-gate 	struct bufarea *bp;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
211*7c478bd9Sstevel@tonic-gate 		if (bp->b_bno == fsbtodb(&sblock, blkno))
212*7c478bd9Sstevel@tonic-gate 			goto foundit;
213*7c478bd9Sstevel@tonic-gate 	for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
214*7c478bd9Sstevel@tonic-gate 		if ((bp->b_flags & B_INUSE) == 0)
215*7c478bd9Sstevel@tonic-gate 			break;
216*7c478bd9Sstevel@tonic-gate 	if (bp == &bufhead) {
217*7c478bd9Sstevel@tonic-gate 		bp = alloc_bufarea();
218*7c478bd9Sstevel@tonic-gate 		if (bp == NULL)
219*7c478bd9Sstevel@tonic-gate 			errexit("deadlocked buffer pool\n");
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 	getblk(bp, blkno, size);
222*7c478bd9Sstevel@tonic-gate 	/* fall through */
223*7c478bd9Sstevel@tonic-gate foundit:
224*7c478bd9Sstevel@tonic-gate 	totalreads++;
225*7c478bd9Sstevel@tonic-gate 	bp->b_cnt++;
226*7c478bd9Sstevel@tonic-gate 	/*
227*7c478bd9Sstevel@tonic-gate 	 * Move the buffer to head of link-list if it isn't
228*7c478bd9Sstevel@tonic-gate 	 * already there.
229*7c478bd9Sstevel@tonic-gate 	 */
230*7c478bd9Sstevel@tonic-gate 	if (bufhead.b_next != bp) {
231*7c478bd9Sstevel@tonic-gate 		bp->b_prev->b_next = bp->b_next;
232*7c478bd9Sstevel@tonic-gate 		bp->b_next->b_prev = bp->b_prev;
233*7c478bd9Sstevel@tonic-gate 		bp->b_prev = &bufhead;
234*7c478bd9Sstevel@tonic-gate 		bp->b_next = bufhead.b_next;
235*7c478bd9Sstevel@tonic-gate 		bufhead.b_next->b_prev = bp;
236*7c478bd9Sstevel@tonic-gate 		bufhead.b_next = bp;
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate 	bp->b_flags |= B_INUSE;
239*7c478bd9Sstevel@tonic-gate 	return (bp);
240*7c478bd9Sstevel@tonic-gate }
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate int
243*7c478bd9Sstevel@tonic-gate brelse(struct bufarea *bp)
244*7c478bd9Sstevel@tonic-gate {
245*7c478bd9Sstevel@tonic-gate 	bp->b_cnt--;
246*7c478bd9Sstevel@tonic-gate 	if (bp->b_cnt == 0) {
247*7c478bd9Sstevel@tonic-gate 		bp->b_flags &= ~B_INUSE;
248*7c478bd9Sstevel@tonic-gate 	}
249*7c478bd9Sstevel@tonic-gate }
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate struct bufarea *
252*7c478bd9Sstevel@tonic-gate getblk(bp, blk, size)
253*7c478bd9Sstevel@tonic-gate 	struct bufarea *bp;
254*7c478bd9Sstevel@tonic-gate 	daddr32_t blk;
255*7c478bd9Sstevel@tonic-gate 	int size;
256*7c478bd9Sstevel@tonic-gate {
257*7c478bd9Sstevel@tonic-gate 	diskaddr_t dblk;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	dblk = fsbtodb(&sblock, blk);
260*7c478bd9Sstevel@tonic-gate 	if (bp->b_bno == dblk)
261*7c478bd9Sstevel@tonic-gate 		return (bp);
262*7c478bd9Sstevel@tonic-gate 	flush(fswritefd, bp);
263*7c478bd9Sstevel@tonic-gate 	diskreads++;
264*7c478bd9Sstevel@tonic-gate 	bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, (long)size);
265*7c478bd9Sstevel@tonic-gate 	bp->b_bno = dblk;
266*7c478bd9Sstevel@tonic-gate 	bp->b_size = size;
267*7c478bd9Sstevel@tonic-gate 	return (bp);
268*7c478bd9Sstevel@tonic-gate }
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate flush(fd, bp)
271*7c478bd9Sstevel@tonic-gate 	int fd;
272*7c478bd9Sstevel@tonic-gate 	struct bufarea *bp;
273*7c478bd9Sstevel@tonic-gate {
274*7c478bd9Sstevel@tonic-gate 	int i, j;
275*7c478bd9Sstevel@tonic-gate 	caddr_t sip;
276*7c478bd9Sstevel@tonic-gate 	long size;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	if (!bp->b_dirty)
279*7c478bd9Sstevel@tonic-gate 		return;
280*7c478bd9Sstevel@tonic-gate 	if (bp->b_errs != 0)
281*7c478bd9Sstevel@tonic-gate 		pfatal("WRITING ZERO'ED BLOCK %lld TO DISK\n", bp->b_bno);
282*7c478bd9Sstevel@tonic-gate 	bp->b_dirty = 0;
283*7c478bd9Sstevel@tonic-gate 	bp->b_errs = 0;
284*7c478bd9Sstevel@tonic-gate 	bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
285*7c478bd9Sstevel@tonic-gate 	if (bp != &sblk)
286*7c478bd9Sstevel@tonic-gate 		return;
287*7c478bd9Sstevel@tonic-gate 	sip = (caddr_t)sblock.fs_u.fs_csp;
288*7c478bd9Sstevel@tonic-gate 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
289*7c478bd9Sstevel@tonic-gate 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
290*7c478bd9Sstevel@tonic-gate 		    sblock.fs_cssize - i : sblock.fs_bsize;
291*7c478bd9Sstevel@tonic-gate 		bwrite(fswritefd, sip,
292*7c478bd9Sstevel@tonic-gate 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
293*7c478bd9Sstevel@tonic-gate 		    size);
294*7c478bd9Sstevel@tonic-gate 		sip += size;
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate }
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate rwerror(mesg, blk)
299*7c478bd9Sstevel@tonic-gate 	char *mesg;
300*7c478bd9Sstevel@tonic-gate 	diskaddr_t blk;
301*7c478bd9Sstevel@tonic-gate {
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	if (preen == 0)
304*7c478bd9Sstevel@tonic-gate 		printf("\n");
305*7c478bd9Sstevel@tonic-gate 	pfatal("CANNOT %s: BLK %lld", mesg, blk);
306*7c478bd9Sstevel@tonic-gate 	if (reply("CONTINUE") == 0)
307*7c478bd9Sstevel@tonic-gate 		errexit("Program terminated\n");
308*7c478bd9Sstevel@tonic-gate }
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate ckfini()
311*7c478bd9Sstevel@tonic-gate {
312*7c478bd9Sstevel@tonic-gate 	struct bufarea *bp, *nbp;
313*7c478bd9Sstevel@tonic-gate 	int cnt = 0;
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/*
316*7c478bd9Sstevel@tonic-gate 	 * Mark the filesystem bad if a re-check is required.
317*7c478bd9Sstevel@tonic-gate 	 */
318*7c478bd9Sstevel@tonic-gate 	if (dirholes && havesb) {
319*7c478bd9Sstevel@tonic-gate 		sblock.fs_clean = FSBAD;
320*7c478bd9Sstevel@tonic-gate 		sblock.fs_state = -(FSOKAY - (long)sblock.fs_time);
321*7c478bd9Sstevel@tonic-gate 		sbdirty();
322*7c478bd9Sstevel@tonic-gate 	}
323*7c478bd9Sstevel@tonic-gate 	flush(fswritefd, &sblk);
324*7c478bd9Sstevel@tonic-gate 	if (havesb && sblk.b_bno != SBOFF / dev_bsize) {
325*7c478bd9Sstevel@tonic-gate 		sblk.b_bno = SBOFF / dev_bsize;
326*7c478bd9Sstevel@tonic-gate 		sbdirty();
327*7c478bd9Sstevel@tonic-gate 		flush(fswritefd, &sblk);
328*7c478bd9Sstevel@tonic-gate 	}
329*7c478bd9Sstevel@tonic-gate 	flush(fswritefd, &cgblk);
330*7c478bd9Sstevel@tonic-gate 	if (cgblk.b_un.b_buf) {
331*7c478bd9Sstevel@tonic-gate 		free(cgblk.b_un.b_buf);
332*7c478bd9Sstevel@tonic-gate 		cgblk.b_un.b_buf = NULL;
333*7c478bd9Sstevel@tonic-gate 	}
334*7c478bd9Sstevel@tonic-gate 	for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
335*7c478bd9Sstevel@tonic-gate 		cnt++;
336*7c478bd9Sstevel@tonic-gate 		flush(fswritefd, bp);
337*7c478bd9Sstevel@tonic-gate 		nbp = bp->b_prev;
338*7c478bd9Sstevel@tonic-gate 		free(bp->b_un.b_buf);
339*7c478bd9Sstevel@tonic-gate 		free((char *)bp);
340*7c478bd9Sstevel@tonic-gate 	}
341*7c478bd9Sstevel@tonic-gate 	pbp = pdirbp = NULL;
342*7c478bd9Sstevel@tonic-gate 	if (bufhead.b_size != cnt)
343*7c478bd9Sstevel@tonic-gate 		errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
344*7c478bd9Sstevel@tonic-gate 	if (debug)
345*7c478bd9Sstevel@tonic-gate 		printf("cache missed %d of %d (%d%%)\n",
346*7c478bd9Sstevel@tonic-gate 		    diskreads, totalreads,
347*7c478bd9Sstevel@tonic-gate 		    totalreads ? diskreads * 100 / totalreads : 0);
348*7c478bd9Sstevel@tonic-gate 	(void) close(fsreadfd);
349*7c478bd9Sstevel@tonic-gate 	(void) close(fswritefd);
350*7c478bd9Sstevel@tonic-gate }
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate bread(fd, buf, blk, size)
353*7c478bd9Sstevel@tonic-gate 	int fd;
354*7c478bd9Sstevel@tonic-gate 	char *buf;
355*7c478bd9Sstevel@tonic-gate 	diskaddr_t blk;
356*7c478bd9Sstevel@tonic-gate 	long size;
357*7c478bd9Sstevel@tonic-gate {
358*7c478bd9Sstevel@tonic-gate 	char *cp;
359*7c478bd9Sstevel@tonic-gate 	int	i;
360*7c478bd9Sstevel@tonic-gate 	int errs;
361*7c478bd9Sstevel@tonic-gate 	offset_t offset = ldbtob(blk);
362*7c478bd9Sstevel@tonic-gate 	offset_t addr;
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	if (debug && (blk < SBLOCK)) {
365*7c478bd9Sstevel@tonic-gate 		char msg[256];
366*7c478bd9Sstevel@tonic-gate 		sprintf(msg, "WARNING: fsck bread() passed blkno < %d (%ld)\n",
367*7c478bd9Sstevel@tonic-gate 		    SBLOCK, blk);
368*7c478bd9Sstevel@tonic-gate 		printf(msg);
369*7c478bd9Sstevel@tonic-gate 	}
370*7c478bd9Sstevel@tonic-gate 	if (llseek(fd, offset, 0) < 0) {
371*7c478bd9Sstevel@tonic-gate 		rwerror("SEEK", blk);
372*7c478bd9Sstevel@tonic-gate 	} else if (read(fd, buf, (int)size) == size)
373*7c478bd9Sstevel@tonic-gate 		return (0);
374*7c478bd9Sstevel@tonic-gate 	rwerror("READ", blk);
375*7c478bd9Sstevel@tonic-gate 	if (llseek(fd, offset, 0) < 0) {
376*7c478bd9Sstevel@tonic-gate 		rwerror("SEEK", blk);
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate 	errs = 0;
379*7c478bd9Sstevel@tonic-gate 	bzero(buf, (size_t)size);
380*7c478bd9Sstevel@tonic-gate 	pwarn("THE FOLLOWING SECTORS COULD NOT BE READ:");
381*7c478bd9Sstevel@tonic-gate 	for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
382*7c478bd9Sstevel@tonic-gate 		addr = ldbtob(blk + i);
383*7c478bd9Sstevel@tonic-gate 		if (llseek(fd, addr, SEEK_CUR) < 0 ||
384*7c478bd9Sstevel@tonic-gate 		    read(fd, cp, (int)secsize) < 0) {
385*7c478bd9Sstevel@tonic-gate 			printf(" %d", blk + i);
386*7c478bd9Sstevel@tonic-gate 			errs++;
387*7c478bd9Sstevel@tonic-gate 		}
388*7c478bd9Sstevel@tonic-gate 	}
389*7c478bd9Sstevel@tonic-gate 	printf("\n");
390*7c478bd9Sstevel@tonic-gate 	return (errs);
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate bwrite(fd, buf, blk, size)
394*7c478bd9Sstevel@tonic-gate 	int fd;
395*7c478bd9Sstevel@tonic-gate 	char *buf;
396*7c478bd9Sstevel@tonic-gate 	diskaddr_t blk;
397*7c478bd9Sstevel@tonic-gate 	long size;
398*7c478bd9Sstevel@tonic-gate {
399*7c478bd9Sstevel@tonic-gate 	int	i;
400*7c478bd9Sstevel@tonic-gate 	int n;
401*7c478bd9Sstevel@tonic-gate 	char *cp;
402*7c478bd9Sstevel@tonic-gate 	offset_t offset = ldbtob(blk);
403*7c478bd9Sstevel@tonic-gate 	offset_t addr;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	if (fd < 0)
406*7c478bd9Sstevel@tonic-gate 		return;
407*7c478bd9Sstevel@tonic-gate 	if (blk < SBLOCK) {
408*7c478bd9Sstevel@tonic-gate 		char msg[256];
409*7c478bd9Sstevel@tonic-gate 		sprintf(msg,
410*7c478bd9Sstevel@tonic-gate 		    "WARNING: Attempt to write illegal blkno %lld on %s\n",
411*7c478bd9Sstevel@tonic-gate 		    blk, devname);
412*7c478bd9Sstevel@tonic-gate 		if (debug)
413*7c478bd9Sstevel@tonic-gate 			printf(msg);
414*7c478bd9Sstevel@tonic-gate 		return;
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 	if (llseek(fd, offset, 0) < 0) {
417*7c478bd9Sstevel@tonic-gate 		rwerror("SEEK", blk);
418*7c478bd9Sstevel@tonic-gate 	} else if (write(fd, buf, (int)size) == size) {
419*7c478bd9Sstevel@tonic-gate 		fsmodified = 1;
420*7c478bd9Sstevel@tonic-gate 		return;
421*7c478bd9Sstevel@tonic-gate 	}
422*7c478bd9Sstevel@tonic-gate 	rwerror("WRITE", blk);
423*7c478bd9Sstevel@tonic-gate 	if (llseek(fd, offset, 0) < 0) {
424*7c478bd9Sstevel@tonic-gate 		rwerror("SEEK", blk);
425*7c478bd9Sstevel@tonic-gate 	}
426*7c478bd9Sstevel@tonic-gate 	pwarn("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
427*7c478bd9Sstevel@tonic-gate 	for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
428*7c478bd9Sstevel@tonic-gate 		n = 0;
429*7c478bd9Sstevel@tonic-gate 		addr = ldbtob(blk + i);
430*7c478bd9Sstevel@tonic-gate 		if (llseek(fd, addr, SEEK_CUR) < 0 ||
431*7c478bd9Sstevel@tonic-gate 		    (n = write(fd, cp, DEV_BSIZE)) < 0) {
432*7c478bd9Sstevel@tonic-gate 			printf(" %d", blk + i);
433*7c478bd9Sstevel@tonic-gate 		} else if (n > 0) {
434*7c478bd9Sstevel@tonic-gate 			fsmodified = 1;
435*7c478bd9Sstevel@tonic-gate 		}
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate 	printf("\n");
439*7c478bd9Sstevel@tonic-gate }
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate /*
442*7c478bd9Sstevel@tonic-gate  * allocate a data block with the specified number of fragments
443*7c478bd9Sstevel@tonic-gate  */
444*7c478bd9Sstevel@tonic-gate daddr32_t
445*7c478bd9Sstevel@tonic-gate allocblk(frags)
446*7c478bd9Sstevel@tonic-gate 	int frags;
447*7c478bd9Sstevel@tonic-gate {
448*7c478bd9Sstevel@tonic-gate 	int i, j, k;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	if (frags <= 0 || frags > sblock.fs_frag)
451*7c478bd9Sstevel@tonic-gate 		return (0);
452*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
453*7c478bd9Sstevel@tonic-gate 		for (j = 0; j <= sblock.fs_frag - frags; j++) {
454*7c478bd9Sstevel@tonic-gate 			if (testbmap(i + j))
455*7c478bd9Sstevel@tonic-gate 				continue;
456*7c478bd9Sstevel@tonic-gate 			for (k = 1; k < frags; k++)
457*7c478bd9Sstevel@tonic-gate 				if (testbmap(i + j + k))
458*7c478bd9Sstevel@tonic-gate 					break;
459*7c478bd9Sstevel@tonic-gate 			if (k < frags) {
460*7c478bd9Sstevel@tonic-gate 				j += k;
461*7c478bd9Sstevel@tonic-gate 				continue;
462*7c478bd9Sstevel@tonic-gate 			}
463*7c478bd9Sstevel@tonic-gate 			for (k = 0; k < frags; k++)
464*7c478bd9Sstevel@tonic-gate 				setbmap(i + j + k);
465*7c478bd9Sstevel@tonic-gate 			n_blks += frags;
466*7c478bd9Sstevel@tonic-gate 			return (i + j);
467*7c478bd9Sstevel@tonic-gate 		}
468*7c478bd9Sstevel@tonic-gate 	}
469*7c478bd9Sstevel@tonic-gate 	return (0);
470*7c478bd9Sstevel@tonic-gate }
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate /*
473*7c478bd9Sstevel@tonic-gate  * Free a previously allocated block
474*7c478bd9Sstevel@tonic-gate  */
475*7c478bd9Sstevel@tonic-gate freeblk(blkno, frags)
476*7c478bd9Sstevel@tonic-gate 	daddr32_t blkno;
477*7c478bd9Sstevel@tonic-gate 	int frags;
478*7c478bd9Sstevel@tonic-gate {
479*7c478bd9Sstevel@tonic-gate 	struct inodesc idesc;
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	idesc.id_blkno = blkno;
482*7c478bd9Sstevel@tonic-gate 	idesc.id_numfrags = frags;
483*7c478bd9Sstevel@tonic-gate 	pass4check(&idesc);
484*7c478bd9Sstevel@tonic-gate }
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate /*
487*7c478bd9Sstevel@tonic-gate  * Find a pathname
488*7c478bd9Sstevel@tonic-gate  */
489*7c478bd9Sstevel@tonic-gate getpathname(namebuf, curdir, ino)
490*7c478bd9Sstevel@tonic-gate 	char *namebuf;
491*7c478bd9Sstevel@tonic-gate 	ino_t curdir, ino;
492*7c478bd9Sstevel@tonic-gate {
493*7c478bd9Sstevel@tonic-gate 	int len;
494*7c478bd9Sstevel@tonic-gate 	char *cp;
495*7c478bd9Sstevel@tonic-gate 	struct inodesc idesc;
496*7c478bd9Sstevel@tonic-gate 	struct inoinfo *inp;
497*7c478bd9Sstevel@tonic-gate 	extern int findname();
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	if (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND) {
500*7c478bd9Sstevel@tonic-gate 		strcpy(namebuf, "?");
501*7c478bd9Sstevel@tonic-gate 		return;
502*7c478bd9Sstevel@tonic-gate 	}
503*7c478bd9Sstevel@tonic-gate 	bzero((char *)&idesc, sizeof (struct inodesc));
504*7c478bd9Sstevel@tonic-gate 	idesc.id_type = DATA;
505*7c478bd9Sstevel@tonic-gate 	cp = &namebuf[MAXPATHLEN - 1];
506*7c478bd9Sstevel@tonic-gate 	*cp = '\0';
507*7c478bd9Sstevel@tonic-gate 	if (curdir != ino) {
508*7c478bd9Sstevel@tonic-gate 		idesc.id_parent = curdir;
509*7c478bd9Sstevel@tonic-gate 		goto namelookup;
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 	while (ino != UFSROOTINO) {
512*7c478bd9Sstevel@tonic-gate 		idesc.id_number = ino;
513*7c478bd9Sstevel@tonic-gate 		idesc.id_func = findino;
514*7c478bd9Sstevel@tonic-gate 		idesc.id_name = "..";
515*7c478bd9Sstevel@tonic-gate 		idesc.id_fix = NOFIX;
516*7c478bd9Sstevel@tonic-gate 		if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) {
517*7c478bd9Sstevel@tonic-gate 			inp = getinoinfo(ino);
518*7c478bd9Sstevel@tonic-gate 			if (inp->i_parent == 0)
519*7c478bd9Sstevel@tonic-gate 				break;
520*7c478bd9Sstevel@tonic-gate 			idesc.id_parent = inp->i_parent;
521*7c478bd9Sstevel@tonic-gate 		}
522*7c478bd9Sstevel@tonic-gate 	namelookup:
523*7c478bd9Sstevel@tonic-gate 		idesc.id_number = idesc.id_parent;
524*7c478bd9Sstevel@tonic-gate 		idesc.id_parent = ino;
525*7c478bd9Sstevel@tonic-gate 		idesc.id_func = findname;
526*7c478bd9Sstevel@tonic-gate 		idesc.id_name = namebuf;
527*7c478bd9Sstevel@tonic-gate 		idesc.id_fix = NOFIX;
528*7c478bd9Sstevel@tonic-gate 		if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
529*7c478bd9Sstevel@tonic-gate 			break;
530*7c478bd9Sstevel@tonic-gate 		len = strlen(namebuf);
531*7c478bd9Sstevel@tonic-gate 		cp -= len;
532*7c478bd9Sstevel@tonic-gate 		if (cp < &namebuf[MAXNAMLEN])
533*7c478bd9Sstevel@tonic-gate 			break;
534*7c478bd9Sstevel@tonic-gate 		bcopy(namebuf, cp, len);
535*7c478bd9Sstevel@tonic-gate 		*--cp = '/';
536*7c478bd9Sstevel@tonic-gate 		ino = idesc.id_number;
537*7c478bd9Sstevel@tonic-gate 	}
538*7c478bd9Sstevel@tonic-gate 	if (ino != UFSROOTINO) {
539*7c478bd9Sstevel@tonic-gate 		strcpy(namebuf, "?");
540*7c478bd9Sstevel@tonic-gate 		return;
541*7c478bd9Sstevel@tonic-gate 	}
542*7c478bd9Sstevel@tonic-gate 	bcopy(cp, namebuf, &namebuf[MAXPATHLEN] - cp);
543*7c478bd9Sstevel@tonic-gate }
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate void
546*7c478bd9Sstevel@tonic-gate catch()
547*7c478bd9Sstevel@tonic-gate {
548*7c478bd9Sstevel@tonic-gate 	ckfini();
549*7c478bd9Sstevel@tonic-gate 	exit(37);
550*7c478bd9Sstevel@tonic-gate }
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate /*
553*7c478bd9Sstevel@tonic-gate  * When preening, allow a single quit to signal
554*7c478bd9Sstevel@tonic-gate  * a special exit after filesystem checks complete
555*7c478bd9Sstevel@tonic-gate  * so that reboot sequence may be interrupted.
556*7c478bd9Sstevel@tonic-gate  */
557*7c478bd9Sstevel@tonic-gate void
558*7c478bd9Sstevel@tonic-gate catchquit()
559*7c478bd9Sstevel@tonic-gate {
560*7c478bd9Sstevel@tonic-gate 	extern returntosingle;
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	printf("returning to single-user after filesystem check\n");
563*7c478bd9Sstevel@tonic-gate 	returntosingle = 1;
564*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGQUIT, SIG_DFL);
565*7c478bd9Sstevel@tonic-gate }
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate /*
568*7c478bd9Sstevel@tonic-gate  * Ignore a single quit signal; wait and flush just in case.
569*7c478bd9Sstevel@tonic-gate  * Used by child processes in preen.
570*7c478bd9Sstevel@tonic-gate  */
571*7c478bd9Sstevel@tonic-gate void
572*7c478bd9Sstevel@tonic-gate voidquit()
573*7c478bd9Sstevel@tonic-gate {
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	sleep(1);
576*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGQUIT, SIG_IGN);
577*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGQUIT, SIG_DFL);
578*7c478bd9Sstevel@tonic-gate }
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate /*
581*7c478bd9Sstevel@tonic-gate  * determine whether an inode should be fixed.
582*7c478bd9Sstevel@tonic-gate  */
583*7c478bd9Sstevel@tonic-gate dofix(idesc, msg)
584*7c478bd9Sstevel@tonic-gate 	struct inodesc *idesc;
585*7c478bd9Sstevel@tonic-gate 	char *msg;
586*7c478bd9Sstevel@tonic-gate {
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	switch (idesc->id_fix) {
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	case DONTKNOW:
591*7c478bd9Sstevel@tonic-gate 		if (idesc->id_type == DATA)
592*7c478bd9Sstevel@tonic-gate 			direrror(idesc->id_number, msg);
593*7c478bd9Sstevel@tonic-gate 		else
594*7c478bd9Sstevel@tonic-gate 			pwarn(msg);
595*7c478bd9Sstevel@tonic-gate 		if (preen) {
596*7c478bd9Sstevel@tonic-gate 			printf(" (SALVAGED)\n");
597*7c478bd9Sstevel@tonic-gate 			idesc->id_fix = FIX;
598*7c478bd9Sstevel@tonic-gate 			return (ALTERED);
599*7c478bd9Sstevel@tonic-gate 		}
600*7c478bd9Sstevel@tonic-gate 		if (reply("SALVAGE") == 0) {
601*7c478bd9Sstevel@tonic-gate 			idesc->id_fix = NOFIX;
602*7c478bd9Sstevel@tonic-gate 			return (0);
603*7c478bd9Sstevel@tonic-gate 		}
604*7c478bd9Sstevel@tonic-gate 		idesc->id_fix = FIX;
605*7c478bd9Sstevel@tonic-gate 		return (ALTERED);
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	case FIX:
608*7c478bd9Sstevel@tonic-gate 		return (ALTERED);
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	case NOFIX:
611*7c478bd9Sstevel@tonic-gate 		return (0);
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	default:
614*7c478bd9Sstevel@tonic-gate 		errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
617*7c478bd9Sstevel@tonic-gate }
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate /* VARARGS1 */
620*7c478bd9Sstevel@tonic-gate errexit(s1, s2, s3, s4)
621*7c478bd9Sstevel@tonic-gate 	char *s1;
622*7c478bd9Sstevel@tonic-gate {
623*7c478bd9Sstevel@tonic-gate 	extern void write_altsb(int);
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	if (errorlocked) {
626*7c478bd9Sstevel@tonic-gate 		if (havesb) {
627*7c478bd9Sstevel@tonic-gate 			sblock.fs_clean = FSBAD;
628*7c478bd9Sstevel@tonic-gate 			sblock.fs_state = -(FSOKAY - (long)sblock.fs_time);
629*7c478bd9Sstevel@tonic-gate 			sbdirty();
630*7c478bd9Sstevel@tonic-gate 			write_altsb(fswritefd);
631*7c478bd9Sstevel@tonic-gate 			flush(fswritefd, &sblk);
632*7c478bd9Sstevel@tonic-gate 		}
633*7c478bd9Sstevel@tonic-gate 	}
634*7c478bd9Sstevel@tonic-gate 	printf(s1, s2, s3, s4);
635*7c478bd9Sstevel@tonic-gate 	exit(39);
636*7c478bd9Sstevel@tonic-gate }
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate /*
639*7c478bd9Sstevel@tonic-gate  * An unexpected inconsistency occured.
640*7c478bd9Sstevel@tonic-gate  * Die if preening, otherwise just print message and continue.
641*7c478bd9Sstevel@tonic-gate  */
642*7c478bd9Sstevel@tonic-gate /* VARARGS1 */
643*7c478bd9Sstevel@tonic-gate pfatal(s, a1, a2, a3)
644*7c478bd9Sstevel@tonic-gate 	char *s;
645*7c478bd9Sstevel@tonic-gate {
646*7c478bd9Sstevel@tonic-gate 	if (preen) {
647*7c478bd9Sstevel@tonic-gate 		printf("%s: ", devname);
648*7c478bd9Sstevel@tonic-gate 		printf(s, a1, a2, a3);
649*7c478bd9Sstevel@tonic-gate 		printf("\n");
650*7c478bd9Sstevel@tonic-gate 		printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
651*7c478bd9Sstevel@tonic-gate 			devname);
652*7c478bd9Sstevel@tonic-gate 		if (havesb) {
653*7c478bd9Sstevel@tonic-gate 			sblock.fs_clean = FSBAD;
654*7c478bd9Sstevel@tonic-gate 			sblock.fs_state = -(FSOKAY - (long)sblock.fs_time);
655*7c478bd9Sstevel@tonic-gate 			sbdirty();
656*7c478bd9Sstevel@tonic-gate 			flush(fswritefd, &sblk);
657*7c478bd9Sstevel@tonic-gate 		}
658*7c478bd9Sstevel@tonic-gate 		exit(36);
659*7c478bd9Sstevel@tonic-gate 	}
660*7c478bd9Sstevel@tonic-gate 	printf(s, a1, a2, a3);
661*7c478bd9Sstevel@tonic-gate }
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate /*
664*7c478bd9Sstevel@tonic-gate  * Pwarn just prints a message when not preening,
665*7c478bd9Sstevel@tonic-gate  * or a warning (preceded by filename) when preening.
666*7c478bd9Sstevel@tonic-gate  */
667*7c478bd9Sstevel@tonic-gate /* VARARGS1 */
668*7c478bd9Sstevel@tonic-gate pwarn(s, a1, a2, a3, a4, a5, a6)
669*7c478bd9Sstevel@tonic-gate 	char *s;
670*7c478bd9Sstevel@tonic-gate {
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 	if (preen)
673*7c478bd9Sstevel@tonic-gate 		printf("%s: ", devname);
674*7c478bd9Sstevel@tonic-gate 	printf(s, a1, a2, a3, a4, a5, a6);
675*7c478bd9Sstevel@tonic-gate }
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate #ifndef lint
678*7c478bd9Sstevel@tonic-gate /*
679*7c478bd9Sstevel@tonic-gate  * Stub for routines from kernel.
680*7c478bd9Sstevel@tonic-gate  */
681*7c478bd9Sstevel@tonic-gate panic(s)
682*7c478bd9Sstevel@tonic-gate 	char *s;
683*7c478bd9Sstevel@tonic-gate {
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	pfatal("INTERNAL INCONSISTENCY:");
686*7c478bd9Sstevel@tonic-gate 	errexit(s);
687*7c478bd9Sstevel@tonic-gate }
688*7c478bd9Sstevel@tonic-gate #define	CE_PANIC 3
689*7c478bd9Sstevel@tonic-gate void
690*7c478bd9Sstevel@tonic-gate cmn_err(level, s)
691*7c478bd9Sstevel@tonic-gate 	int level;
692*7c478bd9Sstevel@tonic-gate 	char *s;
693*7c478bd9Sstevel@tonic-gate {
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 	if (level == CE_PANIC) {
696*7c478bd9Sstevel@tonic-gate 		pfatal("INTERNAL INCONSISTENCY:");
697*7c478bd9Sstevel@tonic-gate 		errexit(s);
698*7c478bd9Sstevel@tonic-gate 	}
699*7c478bd9Sstevel@tonic-gate 	else
700*7c478bd9Sstevel@tonic-gate 		printf(s);
701*7c478bd9Sstevel@tonic-gate }
702*7c478bd9Sstevel@tonic-gate #endif
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate /*
705*7c478bd9Sstevel@tonic-gate  * Check to see if unraw version of name is already mounted.
706*7c478bd9Sstevel@tonic-gate  * Since we do not believe /etc/mnttab, we stat the mount point
707*7c478bd9Sstevel@tonic-gate  * to see if it is really looks mounted.
708*7c478bd9Sstevel@tonic-gate  */
709*7c478bd9Sstevel@tonic-gate mounted(name)
710*7c478bd9Sstevel@tonic-gate 	char *name;
711*7c478bd9Sstevel@tonic-gate {
712*7c478bd9Sstevel@tonic-gate 	int found = 0;
713*7c478bd9Sstevel@tonic-gate 	struct mnttab mnt;
714*7c478bd9Sstevel@tonic-gate 	FILE *mnttab;
715*7c478bd9Sstevel@tonic-gate 	struct stat64 device_stat, mount_stat;
716*7c478bd9Sstevel@tonic-gate 	char *blkname, *unrawname();
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	mnttab = fopen(MNTTAB, "r");
719*7c478bd9Sstevel@tonic-gate 	if (mnttab == NULL) {
720*7c478bd9Sstevel@tonic-gate 		return (0);
721*7c478bd9Sstevel@tonic-gate 	}
722*7c478bd9Sstevel@tonic-gate 	blkname = unrawname(name);
723*7c478bd9Sstevel@tonic-gate 	while ((getmntent(mnttab, &mnt)) == NULL) {
724*7c478bd9Sstevel@tonic-gate 		if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) != 0) {
725*7c478bd9Sstevel@tonic-gate 			continue;
726*7c478bd9Sstevel@tonic-gate 		}
727*7c478bd9Sstevel@tonic-gate 		if (strcmp(blkname, mnt.mnt_special) == 0) {
728*7c478bd9Sstevel@tonic-gate 			stat64(mnt.mnt_mountp, &mount_stat);
729*7c478bd9Sstevel@tonic-gate 			stat64(mnt.mnt_special, &device_stat);
730*7c478bd9Sstevel@tonic-gate 			if (device_stat.st_rdev == mount_stat.st_dev) {
731*7c478bd9Sstevel@tonic-gate 				if (hasmntopt(&mnt, MNTOPT_RO) != 0)
732*7c478bd9Sstevel@tonic-gate 					found = 2;	/* mounted as RO */
733*7c478bd9Sstevel@tonic-gate 				else
734*7c478bd9Sstevel@tonic-gate 					found = 1; 	/* mounted as R/W */
735*7c478bd9Sstevel@tonic-gate 			}
736*7c478bd9Sstevel@tonic-gate 			if (mount_point == NULL) {
737*7c478bd9Sstevel@tonic-gate 				mount_point = strdup(mnt.mnt_mountp);
738*7c478bd9Sstevel@tonic-gate 				if (mount_point == NULL) {
739*7c478bd9Sstevel@tonic-gate 					printf("fsck: memory allocation"
740*7c478bd9Sstevel@tonic-gate 					    " failure\n");
741*7c478bd9Sstevel@tonic-gate 					exit(39);
742*7c478bd9Sstevel@tonic-gate 				}
743*7c478bd9Sstevel@tonic-gate 			}
744*7c478bd9Sstevel@tonic-gate 			break;
745*7c478bd9Sstevel@tonic-gate 		}
746*7c478bd9Sstevel@tonic-gate 	}
747*7c478bd9Sstevel@tonic-gate 	fclose(mnttab);
748*7c478bd9Sstevel@tonic-gate 	return (found);
749*7c478bd9Sstevel@tonic-gate }
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate /*
752*7c478bd9Sstevel@tonic-gate  * Check to see if name corresponds to an entry in vfstab, and that the entry
753*7c478bd9Sstevel@tonic-gate  * does not have option ro.
754*7c478bd9Sstevel@tonic-gate  */
755*7c478bd9Sstevel@tonic-gate writable(name)
756*7c478bd9Sstevel@tonic-gate 	char *name;
757*7c478bd9Sstevel@tonic-gate {
758*7c478bd9Sstevel@tonic-gate 	int rw = 1;
759*7c478bd9Sstevel@tonic-gate 	struct vfstab vfsbuf;
760*7c478bd9Sstevel@tonic-gate 	FILE *vfstab;
761*7c478bd9Sstevel@tonic-gate 	char *blkname, *unrawname();
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 	vfstab = fopen(VFSTAB, "r");
764*7c478bd9Sstevel@tonic-gate 	if (vfstab == NULL) {
765*7c478bd9Sstevel@tonic-gate 		printf("can't open %s\n", VFSTAB);
766*7c478bd9Sstevel@tonic-gate 		return (1);
767*7c478bd9Sstevel@tonic-gate 	}
768*7c478bd9Sstevel@tonic-gate 	blkname = unrawname(name);
769*7c478bd9Sstevel@tonic-gate 	if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0) &&
770*7c478bd9Sstevel@tonic-gate 	    (vfsbuf.vfs_fstype != NULL) &&
771*7c478bd9Sstevel@tonic-gate 	    (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) == 0) &&
772*7c478bd9Sstevel@tonic-gate 	    (hasvfsopt(&vfsbuf, MNTOPT_RO))) {
773*7c478bd9Sstevel@tonic-gate 		rw = 0;
774*7c478bd9Sstevel@tonic-gate 	}
775*7c478bd9Sstevel@tonic-gate 	fclose(vfstab);
776*7c478bd9Sstevel@tonic-gate 	return (rw);
777*7c478bd9Sstevel@tonic-gate }
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate /*
780*7c478bd9Sstevel@tonic-gate  * debugclean
781*7c478bd9Sstevel@tonic-gate  */
782*7c478bd9Sstevel@tonic-gate debugclean()
783*7c478bd9Sstevel@tonic-gate {
784*7c478bd9Sstevel@tonic-gate 	char	s[256];
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 	if (debug == 0)
787*7c478bd9Sstevel@tonic-gate 		return;
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	if ((iscorrupt == 0) && (isdirty == 0))
790*7c478bd9Sstevel@tonic-gate 		return;
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	if ((sblock.fs_clean != FSSTABLE) && (sblock.fs_clean != FSCLEAN) &&
793*7c478bd9Sstevel@tonic-gate 	    (sblock.fs_clean != FSLOG || !islog || !islogok))
794*7c478bd9Sstevel@tonic-gate 		return;
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked)
797*7c478bd9Sstevel@tonic-gate 		return;
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 	sprintf(s,
800*7c478bd9Sstevel@tonic-gate 	    "WARNING: inconsistencies detected on `%s' filesystem %s",
801*7c478bd9Sstevel@tonic-gate 	    sblock.fs_clean == FSSTABLE ? "stable" :
802*7c478bd9Sstevel@tonic-gate 	    sblock.fs_clean == FSLOG ? "logging" :
803*7c478bd9Sstevel@tonic-gate 	    sblock.fs_clean == FSFIX ? "being fixed" : "clean", devname);
804*7c478bd9Sstevel@tonic-gate 	printf("%s\n", s);
805*7c478bd9Sstevel@tonic-gate }
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate /*
808*7c478bd9Sstevel@tonic-gate  * updateclean
809*7c478bd9Sstevel@tonic-gate  *	Carefully and transparently update the clean flag.
810*7c478bd9Sstevel@tonic-gate  */
811*7c478bd9Sstevel@tonic-gate updateclean()
812*7c478bd9Sstevel@tonic-gate {
813*7c478bd9Sstevel@tonic-gate 	struct bufarea	cleanbuf;
814*7c478bd9Sstevel@tonic-gate 	int	size;
815*7c478bd9Sstevel@tonic-gate 	daddr32_t	bno;
816*7c478bd9Sstevel@tonic-gate 	int	fsclean;
817*7c478bd9Sstevel@tonic-gate 	int	fsreclaim;
818*7c478bd9Sstevel@tonic-gate 	int	fsflags;
819*7c478bd9Sstevel@tonic-gate 	int	r;
820*7c478bd9Sstevel@tonic-gate 	daddr32_t	fslogbno;
821*7c478bd9Sstevel@tonic-gate 	offset_t sblkoff;
822*7c478bd9Sstevel@tonic-gate 	time_t t;
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	/*
825*7c478bd9Sstevel@tonic-gate 	 * debug stuff
826*7c478bd9Sstevel@tonic-gate 	 */
827*7c478bd9Sstevel@tonic-gate 	debugclean();
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	/*
830*7c478bd9Sstevel@tonic-gate 	 * set fsclean to its appropriate value
831*7c478bd9Sstevel@tonic-gate 	 */
832*7c478bd9Sstevel@tonic-gate 	fslogbno = sblock.fs_logbno;
833*7c478bd9Sstevel@tonic-gate 	fsclean = sblock.fs_clean;
834*7c478bd9Sstevel@tonic-gate 	fsreclaim = sblock.fs_reclaim;
835*7c478bd9Sstevel@tonic-gate 	fsflags = sblock.fs_flags;
836*7c478bd9Sstevel@tonic-gate 	if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked)
837*7c478bd9Sstevel@tonic-gate 		fsclean = FSACTIVE;
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	/* if ufs log is not okay, clear it */
840*7c478bd9Sstevel@tonic-gate 	if (fslogbno && !(islog && islogok)) {
841*7c478bd9Sstevel@tonic-gate 		fsclean = FSACTIVE;
842*7c478bd9Sstevel@tonic-gate 		fslogbno = 0;
843*7c478bd9Sstevel@tonic-gate 	}
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	/*
846*7c478bd9Sstevel@tonic-gate 	 * if necessary, update fs_clean and fs_state
847*7c478bd9Sstevel@tonic-gate 	 */
848*7c478bd9Sstevel@tonic-gate 	switch (fsclean) {
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	case FSACTIVE:
851*7c478bd9Sstevel@tonic-gate 		if (!iscorrupt) {
852*7c478bd9Sstevel@tonic-gate 			fsclean = FSSTABLE;
853*7c478bd9Sstevel@tonic-gate 			fsreclaim = 0;
854*7c478bd9Sstevel@tonic-gate 		}
855*7c478bd9Sstevel@tonic-gate 		break;
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	case FSCLEAN:
858*7c478bd9Sstevel@tonic-gate 	case FSSTABLE:
859*7c478bd9Sstevel@tonic-gate 		if (iscorrupt)
860*7c478bd9Sstevel@tonic-gate 			fsclean = FSACTIVE;
861*7c478bd9Sstevel@tonic-gate 		else
862*7c478bd9Sstevel@tonic-gate 			fsreclaim = 0;
863*7c478bd9Sstevel@tonic-gate 		break;
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 	case FSLOG:
866*7c478bd9Sstevel@tonic-gate 		if (iscorrupt)
867*7c478bd9Sstevel@tonic-gate 			fsclean = FSACTIVE;
868*7c478bd9Sstevel@tonic-gate 		else if (!islog) {
869*7c478bd9Sstevel@tonic-gate 			fsreclaim = 0;
870*7c478bd9Sstevel@tonic-gate 			fsclean = FSSTABLE;
871*7c478bd9Sstevel@tonic-gate 		} else if (fflag)
872*7c478bd9Sstevel@tonic-gate 			fsreclaim = 0;
873*7c478bd9Sstevel@tonic-gate 		break;
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 	case FSFIX:
876*7c478bd9Sstevel@tonic-gate 		fsreclaim = needs_reclaim;
877*7c478bd9Sstevel@tonic-gate 		fsclean = FSBAD;
878*7c478bd9Sstevel@tonic-gate 		if (errorlocked && !iscorrupt) {
879*7c478bd9Sstevel@tonic-gate 			fsclean = islog? FSLOG: FSCLEAN;
880*7c478bd9Sstevel@tonic-gate 		}
881*7c478bd9Sstevel@tonic-gate 		break;
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 	default:
884*7c478bd9Sstevel@tonic-gate 		if (iscorrupt)
885*7c478bd9Sstevel@tonic-gate 			fsclean = FSACTIVE;
886*7c478bd9Sstevel@tonic-gate 		else {
887*7c478bd9Sstevel@tonic-gate 			fsclean = FSSTABLE;
888*7c478bd9Sstevel@tonic-gate 			fsreclaim = 0;
889*7c478bd9Sstevel@tonic-gate 		}
890*7c478bd9Sstevel@tonic-gate 	}
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	if (largefile_count > 0)
893*7c478bd9Sstevel@tonic-gate 		fsflags |= FSLARGEFILES;
894*7c478bd9Sstevel@tonic-gate 	else
895*7c478bd9Sstevel@tonic-gate 		fsflags &= ~FSLARGEFILES;
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	/*
898*7c478bd9Sstevel@tonic-gate 	 * fs is unchanged, do nothing
899*7c478bd9Sstevel@tonic-gate 	 */
900*7c478bd9Sstevel@tonic-gate 	if (debug)
901*7c478bd9Sstevel@tonic-gate 		printf("** largefile count=%d, fs.fs_flags=%x\n",
902*7c478bd9Sstevel@tonic-gate 		    largefile_count, sblock.fs_flags);
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 	if ((!isdirty) && (fsflags == sblock.fs_flags) &&
905*7c478bd9Sstevel@tonic-gate 	    (fslogbno == sblock.fs_logbno) &&
906*7c478bd9Sstevel@tonic-gate 	    (sblock.fs_clean == fsclean) && (sblock.fs_reclaim == fsreclaim) &&
907*7c478bd9Sstevel@tonic-gate 	    (FSOKAY == (sblock.fs_state + sblock.fs_time))) {
908*7c478bd9Sstevel@tonic-gate 		if (islog && !islogok)
909*7c478bd9Sstevel@tonic-gate 			(void) ioctl(fswritefd, _FIOLOGRESET, NULL);
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 		if (errorlocked) {
912*7c478bd9Sstevel@tonic-gate 			if (!do_errorlock(LOCKFS_ULOCK))
913*7c478bd9Sstevel@tonic-gate 				pwarn(
914*7c478bd9Sstevel@tonic-gate 		    "updateclean(unchanged): unlock(LOCKFS_ULOCK) failed\n");
915*7c478bd9Sstevel@tonic-gate 		}
916*7c478bd9Sstevel@tonic-gate 		return;
917*7c478bd9Sstevel@tonic-gate 	}
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	/*
920*7c478bd9Sstevel@tonic-gate 	 * if user allows, update superblock state
921*7c478bd9Sstevel@tonic-gate 	 */
922*7c478bd9Sstevel@tonic-gate 	if (!isdirty && !preen &&
923*7c478bd9Sstevel@tonic-gate 	    (reply("FILE SYSTEM STATE IN SUPERBLOCK IS WRONG; FIX") == 0))
924*7c478bd9Sstevel@tonic-gate 		return;
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	(void) time(&t);
927*7c478bd9Sstevel@tonic-gate 	sblock.fs_time = (time32_t)t;
928*7c478bd9Sstevel@tonic-gate 	if (debug)
929*7c478bd9Sstevel@tonic-gate 		printclean();
930*7c478bd9Sstevel@tonic-gate 	sblock.fs_logbno = fslogbno;
931*7c478bd9Sstevel@tonic-gate 	sblock.fs_clean = fsclean;
932*7c478bd9Sstevel@tonic-gate 	sblock.fs_state = FSOKAY - (long)sblock.fs_time;
933*7c478bd9Sstevel@tonic-gate 	sblock.fs_reclaim = fsreclaim;
934*7c478bd9Sstevel@tonic-gate 	sblock.fs_flags = fsflags;
935*7c478bd9Sstevel@tonic-gate 
936*7c478bd9Sstevel@tonic-gate 	/*
937*7c478bd9Sstevel@tonic-gate 	 * if superblock can't be written, return
938*7c478bd9Sstevel@tonic-gate 	 */
939*7c478bd9Sstevel@tonic-gate 	if (fswritefd < 0)
940*7c478bd9Sstevel@tonic-gate 		return;
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	/*
943*7c478bd9Sstevel@tonic-gate 	 * read private copy of superblock, update clean flag, and write it
944*7c478bd9Sstevel@tonic-gate 	 */
945*7c478bd9Sstevel@tonic-gate 	bno  = sblk.b_bno;
946*7c478bd9Sstevel@tonic-gate 	size = sblk.b_size;
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 	sblkoff = ldbtob(bno);
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	if ((cleanbuf.b_un.b_buf = malloc(size)) == NULL)
951*7c478bd9Sstevel@tonic-gate 		errexit("out of memory");
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	if (llseek(fsreadfd, sblkoff, 0) == -1)
954*7c478bd9Sstevel@tonic-gate 		return;
955*7c478bd9Sstevel@tonic-gate 	if (read(fsreadfd, cleanbuf.b_un.b_buf, (int)size) != size)
956*7c478bd9Sstevel@tonic-gate 		return;
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	cleanbuf.b_un.b_fs->fs_logbno  = sblock.fs_logbno;
959*7c478bd9Sstevel@tonic-gate 	cleanbuf.b_un.b_fs->fs_clean   = sblock.fs_clean;
960*7c478bd9Sstevel@tonic-gate 	cleanbuf.b_un.b_fs->fs_state   = sblock.fs_state;
961*7c478bd9Sstevel@tonic-gate 	cleanbuf.b_un.b_fs->fs_time    = sblock.fs_time;
962*7c478bd9Sstevel@tonic-gate 	cleanbuf.b_un.b_fs->fs_reclaim = sblock.fs_reclaim;
963*7c478bd9Sstevel@tonic-gate 	cleanbuf.b_un.b_fs->fs_flags   = sblock.fs_flags;
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	if (llseek(fswritefd, sblkoff, 0) == -1)
966*7c478bd9Sstevel@tonic-gate 		return;
967*7c478bd9Sstevel@tonic-gate 	if (write(fswritefd, cleanbuf.b_un.b_buf, (int)size) != size)
968*7c478bd9Sstevel@tonic-gate 		return;
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	/*
971*7c478bd9Sstevel@tonic-gate 	 * 1208040
972*7c478bd9Sstevel@tonic-gate 	 * If we had to use -b to grab an alternate superblock, then we
973*7c478bd9Sstevel@tonic-gate 	 * likely had to do so because of unacceptable differences between
974*7c478bd9Sstevel@tonic-gate 	 * the main and alternate superblocks.  SO, we had better update
975*7c478bd9Sstevel@tonic-gate 	 * the alternate superblock as well, or we'll just fail again
976*7c478bd9Sstevel@tonic-gate 	 * the next time we attempt to run fsck!
977*7c478bd9Sstevel@tonic-gate 	 */
978*7c478bd9Sstevel@tonic-gate 	if (bflag) {
979*7c478bd9Sstevel@tonic-gate 		extern struct bufarea asblk;
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 		if (llseek(fswritefd, ldbtob(asblk.b_bno), 0) == -1)
982*7c478bd9Sstevel@tonic-gate 			return;
983*7c478bd9Sstevel@tonic-gate 		if (write(fswritefd, cleanbuf.b_un.b_buf, (int)size) != size)
984*7c478bd9Sstevel@tonic-gate 			return;
985*7c478bd9Sstevel@tonic-gate 	}
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	if (islog && !islogok)
988*7c478bd9Sstevel@tonic-gate 		(void) ioctl(fswritefd, _FIOLOGRESET, NULL);
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	if (errorlocked) {
991*7c478bd9Sstevel@tonic-gate 		if (!do_errorlock(LOCKFS_ULOCK))
992*7c478bd9Sstevel@tonic-gate 			pwarn(
993*7c478bd9Sstevel@tonic-gate 		    "updateclean(changed): unlock(LOCKFS_ULOCK) failed\n");
994*7c478bd9Sstevel@tonic-gate 	}
995*7c478bd9Sstevel@tonic-gate }
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate /*
998*7c478bd9Sstevel@tonic-gate  * print out clean info
999*7c478bd9Sstevel@tonic-gate  */
1000*7c478bd9Sstevel@tonic-gate printclean()
1001*7c478bd9Sstevel@tonic-gate {
1002*7c478bd9Sstevel@tonic-gate 	char	*s;
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 	if (FSOKAY != (sblock.fs_state + sblock.fs_time) && !errorlocked)
1005*7c478bd9Sstevel@tonic-gate 		s = "unknown";
1006*7c478bd9Sstevel@tonic-gate 	else
1007*7c478bd9Sstevel@tonic-gate 		switch (sblock.fs_clean) {
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 		case FSACTIVE:
1010*7c478bd9Sstevel@tonic-gate 			s = "active";
1011*7c478bd9Sstevel@tonic-gate 			break;
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate 		case FSCLEAN:
1014*7c478bd9Sstevel@tonic-gate 			s = "clean";
1015*7c478bd9Sstevel@tonic-gate 			break;
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 		case FSSTABLE:
1018*7c478bd9Sstevel@tonic-gate 			s = "stable";
1019*7c478bd9Sstevel@tonic-gate 			break;
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 		case FSLOG:
1022*7c478bd9Sstevel@tonic-gate 			s = "logging";
1023*7c478bd9Sstevel@tonic-gate 			break;
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 		case FSBAD:
1026*7c478bd9Sstevel@tonic-gate 			s = "is bad";
1027*7c478bd9Sstevel@tonic-gate 			break;
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 		case FSFIX:
1030*7c478bd9Sstevel@tonic-gate 			s = "being fixed";
1031*7c478bd9Sstevel@tonic-gate 			break;
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 		default:
1034*7c478bd9Sstevel@tonic-gate 			s = "unknown";
1035*7c478bd9Sstevel@tonic-gate 		}
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	if (preen)
1038*7c478bd9Sstevel@tonic-gate 		pwarn("is %s.\n", s);
1039*7c478bd9Sstevel@tonic-gate 	else
1040*7c478bd9Sstevel@tonic-gate 		printf("** %s is %s.\n", devname, s);
1041*7c478bd9Sstevel@tonic-gate }
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate /* see if all numbers */
1044*7c478bd9Sstevel@tonic-gate numbers(yp)
1045*7c478bd9Sstevel@tonic-gate 	char	*yp;
1046*7c478bd9Sstevel@tonic-gate {
1047*7c478bd9Sstevel@tonic-gate 	if (yp == NULL)
1048*7c478bd9Sstevel@tonic-gate 		return (0);
1049*7c478bd9Sstevel@tonic-gate 	while ('0' <= *yp && *yp <= '9')
1050*7c478bd9Sstevel@tonic-gate 		yp++;
1051*7c478bd9Sstevel@tonic-gate 	if (*yp)
1052*7c478bd9Sstevel@tonic-gate 		return (0);
1053*7c478bd9Sstevel@tonic-gate 	return (1);
1054*7c478bd9Sstevel@tonic-gate }
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate is_errorlocked(char *fs)
1057*7c478bd9Sstevel@tonic-gate {
1058*7c478bd9Sstevel@tonic-gate 	struct stat64	 statb;
1059*7c478bd9Sstevel@tonic-gate 	char 		*mountp;
1060*7c478bd9Sstevel@tonic-gate 	static char	*getmountp(char *);
1061*7c478bd9Sstevel@tonic-gate 	char		*unrawname(char *);
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate 	mountp = NULL;
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 	if (!fs)
1066*7c478bd9Sstevel@tonic-gate 		return (0);
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	if (stat64(fs, &statb) < 0)
1069*7c478bd9Sstevel@tonic-gate 		return (0);
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	if (S_ISDIR(statb.st_mode)) {
1072*7c478bd9Sstevel@tonic-gate 		mountp = fs;
1073*7c478bd9Sstevel@tonic-gate 
1074*7c478bd9Sstevel@tonic-gate 	} else if (S_ISBLK(statb.st_mode) || S_ISCHR(statb.st_mode)) {
1075*7c478bd9Sstevel@tonic-gate 		mountp = getmountp(S_ISCHR(statb.st_mode)? unrawname(fs): fs);
1076*7c478bd9Sstevel@tonic-gate 		if (!mountp) {
1077*7c478bd9Sstevel@tonic-gate 			return (0);
1078*7c478bd9Sstevel@tonic-gate 		}
1079*7c478bd9Sstevel@tonic-gate 	} else {
1080*7c478bd9Sstevel@tonic-gate 		return (0);
1081*7c478bd9Sstevel@tonic-gate 	}
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate 	if (elock_combuf == NULL) {
1084*7c478bd9Sstevel@tonic-gate 		elock_combuf =
1085*7c478bd9Sstevel@tonic-gate 			(char *)calloc(LOCKFS_MAXCOMMENTLEN, sizeof (char));
1086*7c478bd9Sstevel@tonic-gate 	} else {
1087*7c478bd9Sstevel@tonic-gate 		elock_combuf =
1088*7c478bd9Sstevel@tonic-gate 			(char *)realloc(elock_combuf, LOCKFS_MAXCOMMENTLEN);
1089*7c478bd9Sstevel@tonic-gate 	}
1090*7c478bd9Sstevel@tonic-gate 
1091*7c478bd9Sstevel@tonic-gate 	if (elock_combuf == NULL)
1092*7c478bd9Sstevel@tonic-gate 		return (0);
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)elock_combuf, LOCKFS_MAXCOMMENTLEN);
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 	elock_mountp = strdup(mountp);
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 	if (mountfd < 0) {
1099*7c478bd9Sstevel@tonic-gate 		if ((mountfd = open64(mountp, O_RDONLY)) == -1)
1100*7c478bd9Sstevel@tonic-gate 			return (0);
1101*7c478bd9Sstevel@tonic-gate 	}
1102*7c478bd9Sstevel@tonic-gate 
1103*7c478bd9Sstevel@tonic-gate 	if (!lfp) {
1104*7c478bd9Sstevel@tonic-gate 		lfp = (struct lockfs *)malloc(sizeof (struct lockfs));
1105*7c478bd9Sstevel@tonic-gate 		if (!lfp)
1106*7c478bd9Sstevel@tonic-gate 			return (0);
1107*7c478bd9Sstevel@tonic-gate 		bzero((caddr_t)lfp, sizeof (struct lockfs));
1108*7c478bd9Sstevel@tonic-gate 	}
1109*7c478bd9Sstevel@tonic-gate 
1110*7c478bd9Sstevel@tonic-gate 	lfp->lf_comlen = LOCKFS_MAXCOMMENTLEN;
1111*7c478bd9Sstevel@tonic-gate 	lfp->lf_comment = elock_combuf;
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate 	if (ioctl(mountfd, _FIOLFSS, lfp) == -1)
1114*7c478bd9Sstevel@tonic-gate 		return (0);
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 	return (LOCKFS_IS_ELOCK(lfp));
1117*7c478bd9Sstevel@tonic-gate }
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate static char *
1120*7c478bd9Sstevel@tonic-gate getmountp(char *dev) {
1121*7c478bd9Sstevel@tonic-gate 	FILE		*vfstab;
1122*7c478bd9Sstevel@tonic-gate 	struct vfstab	 vfsbuf;
1123*7c478bd9Sstevel@tonic-gate 	char		*mountp;
1124*7c478bd9Sstevel@tonic-gate 	int		 rc;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	mountp = NULL;
1127*7c478bd9Sstevel@tonic-gate 	if ((vfstab = fopen(VFSTAB, "r")) == NULL) {
1128*7c478bd9Sstevel@tonic-gate 		return (NULL);
1129*7c478bd9Sstevel@tonic-gate 	}
1130*7c478bd9Sstevel@tonic-gate 	if ((rc = getvfsspec(vfstab, &vfsbuf, dev)) == 0) {
1131*7c478bd9Sstevel@tonic-gate 		if (!(mountp = malloc(MAXPATHLEN)) ||
1132*7c478bd9Sstevel@tonic-gate 		    vfsbuf.vfs_mountp == NULL)
1133*7c478bd9Sstevel@tonic-gate 			return (NULL);
1134*7c478bd9Sstevel@tonic-gate 		strcpy(mountp, vfsbuf.vfs_mountp);
1135*7c478bd9Sstevel@tonic-gate 	} else if (rc == -1) {
1136*7c478bd9Sstevel@tonic-gate 		return (NULL);
1137*7c478bd9Sstevel@tonic-gate 	}
1138*7c478bd9Sstevel@tonic-gate 	fclose(vfstab);
1139*7c478bd9Sstevel@tonic-gate 	return (mountp);
1140*7c478bd9Sstevel@tonic-gate }
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate do_errorlock(int lock_type)
1143*7c478bd9Sstevel@tonic-gate {
1144*7c478bd9Sstevel@tonic-gate 	char		*buf;
1145*7c478bd9Sstevel@tonic-gate 	time_t		 now;
1146*7c478bd9Sstevel@tonic-gate 	struct tm	*local;
1147*7c478bd9Sstevel@tonic-gate 	int		 rc = 0;
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 	if (!elock_combuf)
1150*7c478bd9Sstevel@tonic-gate 		errexit("do_errorlock(%s, %d): unallocated elock_combuf\n",
1151*7c478bd9Sstevel@tonic-gate 			elock_mountp? elock_mountp: "<null>", lock_type);
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 	if (!(buf = (char *)calloc(LOCKFS_MAXCOMMENTLEN, sizeof (char))))
1154*7c478bd9Sstevel@tonic-gate 		errexit("Couldn't alloc memory for temp. lock status buffer\n");
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate 	if (!lfp) {
1157*7c478bd9Sstevel@tonic-gate 		errexit("do_errorlock(%s, %d): lockfs status unallocated\n",
1158*7c478bd9Sstevel@tonic-gate 					elock_mountp, lock_type);
1159*7c478bd9Sstevel@tonic-gate 	}
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 	bcopy(elock_combuf, buf, LOCKFS_MAXCOMMENTLEN-1);
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate 	switch (lock_type) {
1164*7c478bd9Sstevel@tonic-gate 	case LOCKFS_ELOCK:
1165*7c478bd9Sstevel@tonic-gate 		if (time(&now) != (time_t)-1) {
1166*7c478bd9Sstevel@tonic-gate 			if ((local = localtime(&now)) != NULL)
1167*7c478bd9Sstevel@tonic-gate 				sprintf(buf,
1168*7c478bd9Sstevel@tonic-gate 		    "%s [pid:%d fsck start:%02d/%02d/%02d %02d:%02d:%02d",
1169*7c478bd9Sstevel@tonic-gate 				    elock_combuf, pid,
1170*7c478bd9Sstevel@tonic-gate 				    local->tm_mon+1, local->tm_mday,
1171*7c478bd9Sstevel@tonic-gate 				    (local->tm_year % 100), local->tm_hour,
1172*7c478bd9Sstevel@tonic-gate 				    local->tm_min, local->tm_sec);
1173*7c478bd9Sstevel@tonic-gate 			else
1174*7c478bd9Sstevel@tonic-gate 				sprintf(buf, "%s [fsck pid %d",
1175*7c478bd9Sstevel@tonic-gate 							    elock_combuf, pid);
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate 		} else {
1178*7c478bd9Sstevel@tonic-gate 			sprintf(buf, "%s [fsck pid %d", elock_combuf, pid);
1179*7c478bd9Sstevel@tonic-gate 		}
1180*7c478bd9Sstevel@tonic-gate 		break;
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate 	case LOCKFS_ULOCK:
1183*7c478bd9Sstevel@tonic-gate 		if (time(&now) != (time_t)-1) {
1184*7c478bd9Sstevel@tonic-gate 			if ((local = localtime(&now)) != NULL) {
1185*7c478bd9Sstevel@tonic-gate 				sprintf(buf,
1186*7c478bd9Sstevel@tonic-gate 				    "%s, done:%02d/%02d/%02d %02d:%02d:%02d]",
1187*7c478bd9Sstevel@tonic-gate 				    elock_combuf,
1188*7c478bd9Sstevel@tonic-gate 				    local->tm_mon+1, local->tm_mday,
1189*7c478bd9Sstevel@tonic-gate 				    (local->tm_year % 100), local->tm_hour,
1190*7c478bd9Sstevel@tonic-gate 				    local->tm_min, local->tm_sec);
1191*7c478bd9Sstevel@tonic-gate 			} else {
1192*7c478bd9Sstevel@tonic-gate 				sprintf(buf, "%s]", elock_combuf);
1193*7c478bd9Sstevel@tonic-gate 			}
1194*7c478bd9Sstevel@tonic-gate 		} else {
1195*7c478bd9Sstevel@tonic-gate 			sprintf(buf, "%s]", elock_combuf);
1196*7c478bd9Sstevel@tonic-gate 		}
1197*7c478bd9Sstevel@tonic-gate 		if ((rc = ioctl(mountfd, _FIOLFSS, lfp)) == -1) {
1198*7c478bd9Sstevel@tonic-gate 			goto out;
1199*7c478bd9Sstevel@tonic-gate 		}
1200*7c478bd9Sstevel@tonic-gate 		break;
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	default:
1203*7c478bd9Sstevel@tonic-gate 		break;
1204*7c478bd9Sstevel@tonic-gate 	}
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 	bcopy(buf, elock_combuf, LOCKFS_MAXCOMMENTLEN-1);
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	lfp->lf_lock	= lock_type;
1209*7c478bd9Sstevel@tonic-gate 	lfp->lf_comlen	= LOCKFS_MAXCOMMENTLEN;
1210*7c478bd9Sstevel@tonic-gate 	lfp->lf_comment	= elock_combuf;
1211*7c478bd9Sstevel@tonic-gate 	lfp->lf_flags	= 0;
1212*7c478bd9Sstevel@tonic-gate 	errno		= 0;
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 	if ((rc = ioctl(mountfd, _FIOLFS, lfp)) == -1) {
1215*7c478bd9Sstevel@tonic-gate 		if (errno == EINVAL) {
1216*7c478bd9Sstevel@tonic-gate 			pwarn("Another fsck active?\n");
1217*7c478bd9Sstevel@tonic-gate 			iscorrupt = 0;	/* don't go away mad, just go away */
1218*7c478bd9Sstevel@tonic-gate 		} else {
1219*7c478bd9Sstevel@tonic-gate 			pwarn(
1220*7c478bd9Sstevel@tonic-gate 			"do_errorlock(lock_type:%d, %s) failed: errno:%d\n",
1221*7c478bd9Sstevel@tonic-gate 						lock_type, elock_combuf, errno);
1222*7c478bd9Sstevel@tonic-gate 		}
1223*7c478bd9Sstevel@tonic-gate 	}
1224*7c478bd9Sstevel@tonic-gate out:
1225*7c478bd9Sstevel@tonic-gate 	if (buf)
1226*7c478bd9Sstevel@tonic-gate 		free(buf);
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	return (rc != -1);
1229*7c478bd9Sstevel@tonic-gate }
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate /*
1232*7c478bd9Sstevel@tonic-gate  * Shadow inode support.  To `register' a shadow with a client is to note
1233*7c478bd9Sstevel@tonic-gate  * that an inode (the `client') refers to the shadow.  See fsck.h for more
1234*7c478bd9Sstevel@tonic-gate  * on how the shadowclientinfo and shadowclients structures are used.
1235*7c478bd9Sstevel@tonic-gate  */
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate static struct shadowclients *
1238*7c478bd9Sstevel@tonic-gate newshadowclient(struct shadowclients *prev)
1239*7c478bd9Sstevel@tonic-gate {
1240*7c478bd9Sstevel@tonic-gate 	struct shadowclients *rc;
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	rc = (struct shadowclients *)malloc(sizeof (*rc));
1243*7c478bd9Sstevel@tonic-gate 	if (rc == NULL)
1244*7c478bd9Sstevel@tonic-gate 		errexit("newshadowclient: cannot malloc (1)");
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	rc->next = prev;
1247*7c478bd9Sstevel@tonic-gate 	rc->nclients = 0;
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	rc->client = (ino_t *)
1250*7c478bd9Sstevel@tonic-gate 	    malloc(sizeof (ino_t) * maxshadowclients);
1251*7c478bd9Sstevel@tonic-gate 	if (rc->client == NULL)
1252*7c478bd9Sstevel@tonic-gate 		errexit("newshadowclient: cannot malloc (2)");
1253*7c478bd9Sstevel@tonic-gate 
1254*7c478bd9Sstevel@tonic-gate 	return (rc);
1255*7c478bd9Sstevel@tonic-gate }
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate void
1258*7c478bd9Sstevel@tonic-gate registershadowclient(ino_t shadow, ino_t client, struct shadowclientinfo **info)
1259*7c478bd9Sstevel@tonic-gate {
1260*7c478bd9Sstevel@tonic-gate 	struct shadowclientinfo *sci;
1261*7c478bd9Sstevel@tonic-gate 	struct shadowclients *scc;
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	for (sci = *info; sci; sci = sci->next)
1264*7c478bd9Sstevel@tonic-gate 		if (sci->shadow == shadow)
1265*7c478bd9Sstevel@tonic-gate 			break;
1266*7c478bd9Sstevel@tonic-gate 	if (sci == NULL) {
1267*7c478bd9Sstevel@tonic-gate 		sci = (struct shadowclientinfo *)malloc(sizeof (*sci));
1268*7c478bd9Sstevel@tonic-gate 		if (sci == NULL)
1269*7c478bd9Sstevel@tonic-gate 			errexit("registershadowclient: cannot malloc");
1270*7c478bd9Sstevel@tonic-gate 		sci->next = *info;
1271*7c478bd9Sstevel@tonic-gate 		*info = sci;
1272*7c478bd9Sstevel@tonic-gate 		sci->shadow = shadow;
1273*7c478bd9Sstevel@tonic-gate 		sci->totalClients = 0;
1274*7c478bd9Sstevel@tonic-gate 		sci->clients = newshadowclient(NULL);
1275*7c478bd9Sstevel@tonic-gate 	}
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 	sci->totalClients++;
1278*7c478bd9Sstevel@tonic-gate 	scc = sci->clients;
1279*7c478bd9Sstevel@tonic-gate 	if (scc->nclients >= maxshadowclients) {
1280*7c478bd9Sstevel@tonic-gate 		scc = newshadowclient(sci->clients);
1281*7c478bd9Sstevel@tonic-gate 		sci->clients = scc;
1282*7c478bd9Sstevel@tonic-gate 	}
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate 	scc->client[scc->nclients++] = client;
1285*7c478bd9Sstevel@tonic-gate }
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate /*
1288*7c478bd9Sstevel@tonic-gate  * Allocate more buffer as need arises but allocate one at a time.
1289*7c478bd9Sstevel@tonic-gate  * This is done to make sure that fsck does not exit with error if it
1290*7c478bd9Sstevel@tonic-gate  * needs more buffer to complete it's task.
1291*7c478bd9Sstevel@tonic-gate  */
1292*7c478bd9Sstevel@tonic-gate static struct bufarea *
1293*7c478bd9Sstevel@tonic-gate alloc_bufarea()
1294*7c478bd9Sstevel@tonic-gate {
1295*7c478bd9Sstevel@tonic-gate 	struct bufarea *bp;
1296*7c478bd9Sstevel@tonic-gate 	char *bufp;
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 	bp = (struct bufarea *)malloc(sizeof (struct bufarea));
1299*7c478bd9Sstevel@tonic-gate 	bufp = malloc((unsigned int)sblock.fs_bsize);
1300*7c478bd9Sstevel@tonic-gate 	if (bp == NULL || bufp == NULL) {
1301*7c478bd9Sstevel@tonic-gate 		if (bp)
1302*7c478bd9Sstevel@tonic-gate 			free((char *)bp);
1303*7c478bd9Sstevel@tonic-gate 		if (bufp)
1304*7c478bd9Sstevel@tonic-gate 			free(bufp);
1305*7c478bd9Sstevel@tonic-gate 		return (NULL);
1306*7c478bd9Sstevel@tonic-gate 	}
1307*7c478bd9Sstevel@tonic-gate 	bp->b_un.b_buf = bufp;
1308*7c478bd9Sstevel@tonic-gate 	bp->b_prev = &bufhead;
1309*7c478bd9Sstevel@tonic-gate 	bp->b_next = bufhead.b_next;
1310*7c478bd9Sstevel@tonic-gate 	bufhead.b_next->b_prev = bp;
1311*7c478bd9Sstevel@tonic-gate 	bufhead.b_next = bp;
1312*7c478bd9Sstevel@tonic-gate 	initbarea(bp);
1313*7c478bd9Sstevel@tonic-gate 	bufhead.b_size++;
1314*7c478bd9Sstevel@tonic-gate 	return (bp);
1315*7c478bd9Sstevel@tonic-gate }
1316