xref: /onnv-gate/usr/src/cmd/fs.d/udfs/fsck/utilities.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 1999 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
8*0Sstevel@tonic-gate 
9*0Sstevel@tonic-gate /*
10*0Sstevel@tonic-gate  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11*0Sstevel@tonic-gate  * All rights reserved.
12*0Sstevel@tonic-gate  *
13*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
14*0Sstevel@tonic-gate  * provided that: (1) source distributions retain this entire copyright
15*0Sstevel@tonic-gate  * notice and comment, and (2) distributions including binaries display
16*0Sstevel@tonic-gate  * the following acknowledgement:  ``This product includes software
17*0Sstevel@tonic-gate  * developed by the University of California, Berkeley and its contributors''
18*0Sstevel@tonic-gate  * in the documentation or other materials provided with the distribution
19*0Sstevel@tonic-gate  * and in all advertising materials mentioning features or use of this
20*0Sstevel@tonic-gate  * software. Neither the name of the University nor the names of its
21*0Sstevel@tonic-gate  * contributors may be used to endorse or promote products derived
22*0Sstevel@tonic-gate  * from this software without specific prior written permission.
23*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25*0Sstevel@tonic-gate  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26*0Sstevel@tonic-gate  */
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate #include <stdio.h>
31*0Sstevel@tonic-gate #include <fcntl.h>
32*0Sstevel@tonic-gate #include <errno.h>
33*0Sstevel@tonic-gate #include <unistd.h>
34*0Sstevel@tonic-gate #include <stdlib.h>
35*0Sstevel@tonic-gate #include <fcntl.h>
36*0Sstevel@tonic-gate #include <string.h>
37*0Sstevel@tonic-gate #include <strings.h>
38*0Sstevel@tonic-gate #include <ctype.h>
39*0Sstevel@tonic-gate #include <malloc.h>
40*0Sstevel@tonic-gate #include <signal.h>
41*0Sstevel@tonic-gate #include <sys/param.h>
42*0Sstevel@tonic-gate #include <sys/types.h>
43*0Sstevel@tonic-gate #include <sys/mntent.h>
44*0Sstevel@tonic-gate #include <sys/filio.h>
45*0Sstevel@tonic-gate #include <sys/vnode.h>
46*0Sstevel@tonic-gate #include <sys/mnttab.h>
47*0Sstevel@tonic-gate #include <sys/types.h>
48*0Sstevel@tonic-gate #include <sys/stat.h>
49*0Sstevel@tonic-gate #include <sys/vfstab.h>
50*0Sstevel@tonic-gate #include <sys/sysmacros.h>
51*0Sstevel@tonic-gate #include <sys/fs/udf_volume.h>
52*0Sstevel@tonic-gate #include "fsck.h"
53*0Sstevel@tonic-gate #include <sys/lockfs.h>
54*0Sstevel@tonic-gate #include <locale.h>
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate extern int32_t	verifytag(struct tag *, uint32_t, struct tag *, int);
57*0Sstevel@tonic-gate extern char	*tagerrs[];
58*0Sstevel@tonic-gate extern void	maketag(struct tag *, struct tag *);
59*0Sstevel@tonic-gate extern char	*hasvfsopt(struct vfstab *, char *);
60*0Sstevel@tonic-gate static struct bufarea *getdatablk(daddr_t, long);
61*0Sstevel@tonic-gate static struct bufarea *getblk(struct bufarea *, daddr_t, long);
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate void	flush(int32_t, struct bufarea *);
64*0Sstevel@tonic-gate int32_t	bread(int32_t, char *, daddr_t, long);
65*0Sstevel@tonic-gate void	bwrite(int, char *, daddr_t, long);
66*0Sstevel@tonic-gate static int32_t	getline(FILE *, char *, int32_t);
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate static long	diskreads, totalreads;	/* Disk cache statistics */
69*0Sstevel@tonic-gate offset_t	llseek();
70*0Sstevel@tonic-gate extern unsigned int largefile_count;
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate  * An unexpected inconsistency occured.
74*0Sstevel@tonic-gate  * Die if preening, otherwise just print message and continue.
75*0Sstevel@tonic-gate  */
76*0Sstevel@tonic-gate /* VARARGS1 */
77*0Sstevel@tonic-gate void
78*0Sstevel@tonic-gate pfatal(s, a1, a2, a3)
79*0Sstevel@tonic-gate 	char *s;
80*0Sstevel@tonic-gate {
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	if (preen) {
83*0Sstevel@tonic-gate 		(void) printf("%s: ", devname);
84*0Sstevel@tonic-gate 		(void) printf(s, a1, a2, a3);
85*0Sstevel@tonic-gate 		(void) printf("\n");
86*0Sstevel@tonic-gate 		(void) printf(
87*0Sstevel@tonic-gate 		    gettext("%s: UNEXPECTED INCONSISTENCY; RUN fsck "
88*0Sstevel@tonic-gate 			"MANUALLY.\n"), devname);
89*0Sstevel@tonic-gate 		exit(36);
90*0Sstevel@tonic-gate 	}
91*0Sstevel@tonic-gate 	(void) printf(s, a1, a2, a3);
92*0Sstevel@tonic-gate }
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate /*
95*0Sstevel@tonic-gate  * Pwarn just prints a message when not preening,
96*0Sstevel@tonic-gate  * or a warning (preceded by filename) when preening.
97*0Sstevel@tonic-gate  */
98*0Sstevel@tonic-gate /* VARARGS1 */
99*0Sstevel@tonic-gate void
100*0Sstevel@tonic-gate pwarn(s, a1, a2, a3, a4, a5, a6)
101*0Sstevel@tonic-gate 	char *s;
102*0Sstevel@tonic-gate {
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	if (preen)
105*0Sstevel@tonic-gate 		(void) printf("%s: ", devname);
106*0Sstevel@tonic-gate 	(void) printf(s, a1, a2, a3, a4, a5, a6);
107*0Sstevel@tonic-gate }
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate /* VARARGS1 */
111*0Sstevel@tonic-gate void
112*0Sstevel@tonic-gate errexit(s1, s2, s3, s4)
113*0Sstevel@tonic-gate 	char *s1;
114*0Sstevel@tonic-gate {
115*0Sstevel@tonic-gate 	(void) printf(s1, s2, s3, s4);
116*0Sstevel@tonic-gate 	exit(39);
117*0Sstevel@tonic-gate }
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate void
120*0Sstevel@tonic-gate markbusy(daddr_t block, long count)
121*0Sstevel@tonic-gate {
122*0Sstevel@tonic-gate 	register int i;
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	count = roundup(count, secsize) / secsize;
125*0Sstevel@tonic-gate 	for (i = 0; i < count; i++, block++) {
126*0Sstevel@tonic-gate 		if ((unsigned)block > part_len) {
127*0Sstevel@tonic-gate 			pwarn(gettext("Block %lx out of range\n"), block);
128*0Sstevel@tonic-gate 			break;
129*0Sstevel@tonic-gate 		}
130*0Sstevel@tonic-gate 		if (testbusy(block))
131*0Sstevel@tonic-gate 			pwarn(gettext("Dup block %lx\n"), block);
132*0Sstevel@tonic-gate 		else {
133*0Sstevel@tonic-gate 			n_blks++;
134*0Sstevel@tonic-gate 			setbusy(block);
135*0Sstevel@tonic-gate 		}
136*0Sstevel@tonic-gate 	}
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate void
140*0Sstevel@tonic-gate printfree()
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate 	int i, startfree, endfree;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	startfree = -1;
145*0Sstevel@tonic-gate 	for (i = 0; i < part_len; i++) {
146*0Sstevel@tonic-gate 		if (!testbusy(i)) {
147*0Sstevel@tonic-gate 			if (startfree <= 0)
148*0Sstevel@tonic-gate 				startfree = i;
149*0Sstevel@tonic-gate 			endfree = i;
150*0Sstevel@tonic-gate 		} else if (startfree >= 0) {
151*0Sstevel@tonic-gate 			(void) printf("free: %x-%x\n", startfree, endfree - 1);
152*0Sstevel@tonic-gate 			startfree = -1;
153*0Sstevel@tonic-gate 		}
154*0Sstevel@tonic-gate 	}
155*0Sstevel@tonic-gate 	if (startfree >= 0) {
156*0Sstevel@tonic-gate 		(void) printf("free: %x-%x\n", startfree, endfree);
157*0Sstevel@tonic-gate 	}
158*0Sstevel@tonic-gate }
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate struct bufarea *
161*0Sstevel@tonic-gate getfilentry(uint32_t block, int len)
162*0Sstevel@tonic-gate {
163*0Sstevel@tonic-gate 	struct bufarea *bp;
164*0Sstevel@tonic-gate 	struct file_entry *fp;
165*0Sstevel@tonic-gate 	int err;
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	if (len > fsbsize) {
168*0Sstevel@tonic-gate 		(void) printf(gettext("File entry at %x is too long "
169*0Sstevel@tonic-gate 			"(%d bytes)\n"), block, len);
170*0Sstevel@tonic-gate 		len = fsbsize;
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate 	bp = getdatablk((daddr_t)(block + part_start), fsbsize);
173*0Sstevel@tonic-gate 	if (bp->b_errs) {
174*0Sstevel@tonic-gate 		bp->b_flags &= ~B_INUSE;
175*0Sstevel@tonic-gate 		return (NULL);
176*0Sstevel@tonic-gate 	}
177*0Sstevel@tonic-gate 	/* LINTED */
178*0Sstevel@tonic-gate 	fp = (struct file_entry *)bp->b_un.b_buf;
179*0Sstevel@tonic-gate 	err = verifytag(&fp->fe_tag, block, &fp->fe_tag, UD_FILE_ENTRY);
180*0Sstevel@tonic-gate 	if (err) {
181*0Sstevel@tonic-gate 		(void) printf(gettext("Tag error %s or bad file entry, "
182*0Sstevel@tonic-gate 			"tag=%d\n"), tagerrs[err], fp->fe_tag.tag_id);
183*0Sstevel@tonic-gate 		bp->b_flags &= ~B_INUSE;
184*0Sstevel@tonic-gate 		return (NULL);
185*0Sstevel@tonic-gate 	}
186*0Sstevel@tonic-gate 	return (bp);
187*0Sstevel@tonic-gate }
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate void
190*0Sstevel@tonic-gate putfilentry(struct bufarea *bp)
191*0Sstevel@tonic-gate {
192*0Sstevel@tonic-gate 	struct file_entry *fp;
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	/* LINTED */
195*0Sstevel@tonic-gate 	fp = (struct file_entry *)bp->b_un.b_buf;
196*0Sstevel@tonic-gate 	maketag(&fp->fe_tag, &fp->fe_tag);
197*0Sstevel@tonic-gate }
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate int32_t
201*0Sstevel@tonic-gate reply(char *question)
202*0Sstevel@tonic-gate {
203*0Sstevel@tonic-gate 	char line[80];
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	if (preen)
206*0Sstevel@tonic-gate 		pfatal(gettext("INTERNAL ERROR: GOT TO reply()"));
207*0Sstevel@tonic-gate 	(void) printf("\n%s? ", question);
208*0Sstevel@tonic-gate 	if (nflag || fswritefd < 0) {
209*0Sstevel@tonic-gate 		(void) printf(gettext(" no\n\n"));
210*0Sstevel@tonic-gate 		iscorrupt = 1;		/* known to be corrupt */
211*0Sstevel@tonic-gate 		return (0);
212*0Sstevel@tonic-gate 	}
213*0Sstevel@tonic-gate 	if (yflag) {
214*0Sstevel@tonic-gate 		(void) printf(gettext(" yes\n\n"));
215*0Sstevel@tonic-gate 		return (1);
216*0Sstevel@tonic-gate 	}
217*0Sstevel@tonic-gate 	if (getline(stdin, line, sizeof (line)) == EOF)
218*0Sstevel@tonic-gate 		errexit("\n");
219*0Sstevel@tonic-gate 	(void) printf("\n");
220*0Sstevel@tonic-gate 	if (line[0] == 'y' || line[0] == 'Y')
221*0Sstevel@tonic-gate 		return (1);
222*0Sstevel@tonic-gate 	else {
223*0Sstevel@tonic-gate 		iscorrupt = 1;		/* known to be corrupt */
224*0Sstevel@tonic-gate 		return (0);
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate }
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate int32_t
229*0Sstevel@tonic-gate getline(FILE *fp, char *loc, int32_t maxlen)
230*0Sstevel@tonic-gate {
231*0Sstevel@tonic-gate 	register n;
232*0Sstevel@tonic-gate 	register char *p, *lastloc;
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	p = loc;
235*0Sstevel@tonic-gate 	lastloc = &p[maxlen-1];
236*0Sstevel@tonic-gate 	while ((n = getc(fp)) != '\n') {
237*0Sstevel@tonic-gate 		if (n == EOF)
238*0Sstevel@tonic-gate 			return (EOF);
239*0Sstevel@tonic-gate 		if (!isspace(n) && p < lastloc)
240*0Sstevel@tonic-gate 			*p++ = n;
241*0Sstevel@tonic-gate 	}
242*0Sstevel@tonic-gate 	*p = 0;
243*0Sstevel@tonic-gate 	return (p - loc);
244*0Sstevel@tonic-gate }
245*0Sstevel@tonic-gate /*
246*0Sstevel@tonic-gate  * Malloc buffers and set up cache.
247*0Sstevel@tonic-gate  */
248*0Sstevel@tonic-gate void
249*0Sstevel@tonic-gate bufinit()
250*0Sstevel@tonic-gate {
251*0Sstevel@tonic-gate 	register struct bufarea *bp;
252*0Sstevel@tonic-gate 	long bufcnt, i;
253*0Sstevel@tonic-gate 	char *bufp;
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	bufp = malloc((unsigned int)fsbsize);
256*0Sstevel@tonic-gate 	if (bufp == 0)
257*0Sstevel@tonic-gate 		errexit(gettext("cannot allocate buffer pool\n"));
258*0Sstevel@tonic-gate 	bufhead.b_next = bufhead.b_prev = &bufhead;
259*0Sstevel@tonic-gate 	bufcnt = MAXBUFSPACE / fsbsize;
260*0Sstevel@tonic-gate 	if (bufcnt < MINBUFS)
261*0Sstevel@tonic-gate 		bufcnt = MINBUFS;
262*0Sstevel@tonic-gate 	for (i = 0; i < bufcnt; i++) {
263*0Sstevel@tonic-gate 		bp = (struct bufarea *)malloc(sizeof (struct bufarea));
264*0Sstevel@tonic-gate 		bufp = malloc((unsigned int)fsbsize);
265*0Sstevel@tonic-gate 		if (bp == NULL || bufp == NULL) {
266*0Sstevel@tonic-gate 			if (i >= MINBUFS)
267*0Sstevel@tonic-gate 				break;
268*0Sstevel@tonic-gate 			errexit(gettext("cannot allocate buffer pool\n"));
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 		bp->b_un.b_buf = bufp;
271*0Sstevel@tonic-gate 		bp->b_prev = &bufhead;
272*0Sstevel@tonic-gate 		bp->b_next = bufhead.b_next;
273*0Sstevel@tonic-gate 		bufhead.b_next->b_prev = bp;
274*0Sstevel@tonic-gate 		bufhead.b_next = bp;
275*0Sstevel@tonic-gate 		initbarea(bp);
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 	bufhead.b_size = i;	/* save number of buffers */
278*0Sstevel@tonic-gate 	pbp = pdirbp = NULL;
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate /*
282*0Sstevel@tonic-gate  * Manage a cache of directory blocks.
283*0Sstevel@tonic-gate  */
284*0Sstevel@tonic-gate static struct bufarea *
285*0Sstevel@tonic-gate getdatablk(daddr_t blkno, long size)
286*0Sstevel@tonic-gate {
287*0Sstevel@tonic-gate 	register struct bufarea *bp;
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
290*0Sstevel@tonic-gate 		if (bp->b_bno == fsbtodb(blkno))
291*0Sstevel@tonic-gate 			goto foundit;
292*0Sstevel@tonic-gate 	for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
293*0Sstevel@tonic-gate 		if ((bp->b_flags & B_INUSE) == 0)
294*0Sstevel@tonic-gate 			break;
295*0Sstevel@tonic-gate 	if (bp == &bufhead)
296*0Sstevel@tonic-gate 		errexit(gettext("deadlocked buffer pool\n"));
297*0Sstevel@tonic-gate 	(void) getblk(bp, blkno, size);
298*0Sstevel@tonic-gate 	/* fall through */
299*0Sstevel@tonic-gate foundit:
300*0Sstevel@tonic-gate 	totalreads++;
301*0Sstevel@tonic-gate 	bp->b_prev->b_next = bp->b_next;
302*0Sstevel@tonic-gate 	bp->b_next->b_prev = bp->b_prev;
303*0Sstevel@tonic-gate 	bp->b_prev = &bufhead;
304*0Sstevel@tonic-gate 	bp->b_next = bufhead.b_next;
305*0Sstevel@tonic-gate 	bufhead.b_next->b_prev = bp;
306*0Sstevel@tonic-gate 	bufhead.b_next = bp;
307*0Sstevel@tonic-gate 	bp->b_flags |= B_INUSE;
308*0Sstevel@tonic-gate 	return (bp);
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate static struct bufarea *
312*0Sstevel@tonic-gate getblk(struct bufarea *bp, daddr_t blk, long size)
313*0Sstevel@tonic-gate {
314*0Sstevel@tonic-gate 	daddr_t dblk;
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	dblk = fsbtodb(blk);
317*0Sstevel@tonic-gate 	if (bp->b_bno == dblk)
318*0Sstevel@tonic-gate 		return (bp);
319*0Sstevel@tonic-gate 	flush(fswritefd, bp);
320*0Sstevel@tonic-gate 	diskreads++;
321*0Sstevel@tonic-gate 	bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
322*0Sstevel@tonic-gate 	bp->b_bno = dblk;
323*0Sstevel@tonic-gate 	bp->b_size = size;
324*0Sstevel@tonic-gate 	return (bp);
325*0Sstevel@tonic-gate }
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate void
328*0Sstevel@tonic-gate flush(int32_t fd, struct bufarea *bp)
329*0Sstevel@tonic-gate {
330*0Sstevel@tonic-gate 	if (!bp->b_dirty)
331*0Sstevel@tonic-gate 		return;
332*0Sstevel@tonic-gate 	if (bp->b_errs != 0)
333*0Sstevel@tonic-gate 		pfatal(gettext("WRITING ZERO'ED BLOCK %d TO DISK\n"),
334*0Sstevel@tonic-gate 			bp->b_bno);
335*0Sstevel@tonic-gate 	bp->b_dirty = 0;
336*0Sstevel@tonic-gate 	bp->b_errs = 0;
337*0Sstevel@tonic-gate 	bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate static void
341*0Sstevel@tonic-gate rwerror(char *mesg, daddr_t blk)
342*0Sstevel@tonic-gate {
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	if (preen == 0)
345*0Sstevel@tonic-gate 		(void) printf("\n");
346*0Sstevel@tonic-gate 	pfatal(gettext("CANNOT %s: BLK %ld"), mesg, blk);
347*0Sstevel@tonic-gate 	if (reply(gettext("CONTINUE")) == 0)
348*0Sstevel@tonic-gate 		errexit(gettext("Program terminated\n"));
349*0Sstevel@tonic-gate }
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate void
352*0Sstevel@tonic-gate ckfini()
353*0Sstevel@tonic-gate {
354*0Sstevel@tonic-gate 	struct bufarea *bp, *nbp;
355*0Sstevel@tonic-gate 	int cnt = 0;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
358*0Sstevel@tonic-gate 		cnt++;
359*0Sstevel@tonic-gate 		flush(fswritefd, bp);
360*0Sstevel@tonic-gate 		nbp = bp->b_prev;
361*0Sstevel@tonic-gate 		free(bp->b_un.b_buf);
362*0Sstevel@tonic-gate 		free((char *)bp);
363*0Sstevel@tonic-gate 	}
364*0Sstevel@tonic-gate 	pbp = pdirbp = NULL;
365*0Sstevel@tonic-gate 	if (bufhead.b_size != cnt)
366*0Sstevel@tonic-gate 		errexit(gettext("Panic: lost %d buffers\n"),
367*0Sstevel@tonic-gate 			bufhead.b_size - cnt);
368*0Sstevel@tonic-gate 	if (debug)
369*0Sstevel@tonic-gate 		(void) printf("cache missed %ld of %ld (%ld%%)\n",
370*0Sstevel@tonic-gate 		    diskreads, totalreads,
371*0Sstevel@tonic-gate 		    totalreads ? diskreads * 100 / totalreads : 0);
372*0Sstevel@tonic-gate 	(void) close(fsreadfd);
373*0Sstevel@tonic-gate 	(void) close(fswritefd);
374*0Sstevel@tonic-gate }
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate int32_t
377*0Sstevel@tonic-gate bread(int fd, char *buf, daddr_t blk, long size)
378*0Sstevel@tonic-gate {
379*0Sstevel@tonic-gate 	char *cp;
380*0Sstevel@tonic-gate 	int i, errs;
381*0Sstevel@tonic-gate 	offset_t offset = ldbtob(blk);
382*0Sstevel@tonic-gate 	offset_t addr;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	if (llseek(fd, offset, 0) < 0)
385*0Sstevel@tonic-gate 		rwerror(gettext("SEEK"), blk);
386*0Sstevel@tonic-gate 	else if (read(fd, buf, (int)size) == size)
387*0Sstevel@tonic-gate 		return (0);
388*0Sstevel@tonic-gate 	rwerror(gettext("READ"), blk);
389*0Sstevel@tonic-gate 	if (llseek(fd, offset, 0) < 0)
390*0Sstevel@tonic-gate 		rwerror(gettext("SEEK"), blk);
391*0Sstevel@tonic-gate 	errs = 0;
392*0Sstevel@tonic-gate 	bzero(buf, (int)size);
393*0Sstevel@tonic-gate 	pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE READ:"));
394*0Sstevel@tonic-gate 	for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
395*0Sstevel@tonic-gate 		addr = ldbtob(blk + i);
396*0Sstevel@tonic-gate 		if (llseek(fd, addr, SEEK_CUR) < 0 ||
397*0Sstevel@tonic-gate 		    read(fd, cp, (int)secsize) < 0) {
398*0Sstevel@tonic-gate 			(void) printf(" %ld", blk + i);
399*0Sstevel@tonic-gate 			errs++;
400*0Sstevel@tonic-gate 		}
401*0Sstevel@tonic-gate 	}
402*0Sstevel@tonic-gate 	(void) printf("\n");
403*0Sstevel@tonic-gate 	return (errs);
404*0Sstevel@tonic-gate }
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate void
407*0Sstevel@tonic-gate bwrite(int fd, char *buf, daddr_t blk, long size)
408*0Sstevel@tonic-gate {
409*0Sstevel@tonic-gate 	int i, n;
410*0Sstevel@tonic-gate 	char *cp;
411*0Sstevel@tonic-gate 	offset_t offset = ldbtob(blk);
412*0Sstevel@tonic-gate 	offset_t addr;
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	if (fd < 0)
415*0Sstevel@tonic-gate 		return;
416*0Sstevel@tonic-gate 	if (llseek(fd, offset, 0) < 0)
417*0Sstevel@tonic-gate 		rwerror(gettext("SEEK"), blk);
418*0Sstevel@tonic-gate 	else if (write(fd, buf, (int)size) == size) {
419*0Sstevel@tonic-gate 		fsmodified = 1;
420*0Sstevel@tonic-gate 		return;
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 	rwerror(gettext("WRITE"), blk);
423*0Sstevel@tonic-gate 	if (llseek(fd, offset, 0) < 0)
424*0Sstevel@tonic-gate 		rwerror(gettext("SEEK"), blk);
425*0Sstevel@tonic-gate 	pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"));
426*0Sstevel@tonic-gate 	for (cp = buf, i = 0; i < btodb(size); i++, cp += DEV_BSIZE) {
427*0Sstevel@tonic-gate 		n = 0;
428*0Sstevel@tonic-gate 		addr = ldbtob(blk + i);
429*0Sstevel@tonic-gate 		if (llseek(fd, addr, SEEK_CUR) < 0 ||
430*0Sstevel@tonic-gate 		    (n = write(fd, cp, DEV_BSIZE)) < 0) {
431*0Sstevel@tonic-gate 			(void) printf(" %ld", blk + i);
432*0Sstevel@tonic-gate 		} else if (n > 0) {
433*0Sstevel@tonic-gate 			fsmodified = 1;
434*0Sstevel@tonic-gate 		}
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	}
437*0Sstevel@tonic-gate 	(void) printf("\n");
438*0Sstevel@tonic-gate }
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate void
441*0Sstevel@tonic-gate catch()
442*0Sstevel@tonic-gate {
443*0Sstevel@tonic-gate 	ckfini();
444*0Sstevel@tonic-gate 	exit(37);
445*0Sstevel@tonic-gate }
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate /*
448*0Sstevel@tonic-gate  * When preening, allow a single quit to signal
449*0Sstevel@tonic-gate  * a special exit after filesystem checks complete
450*0Sstevel@tonic-gate  * so that reboot sequence may be interrupted.
451*0Sstevel@tonic-gate  */
452*0Sstevel@tonic-gate void
453*0Sstevel@tonic-gate catchquit()
454*0Sstevel@tonic-gate {
455*0Sstevel@tonic-gate 	extern returntosingle;
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	(void) printf(gettext("returning to single-user after filesystem "
458*0Sstevel@tonic-gate 		"check\n"));
459*0Sstevel@tonic-gate 	returntosingle = 1;
460*0Sstevel@tonic-gate 	(void) signal(SIGQUIT, SIG_DFL);
461*0Sstevel@tonic-gate }
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate /*
464*0Sstevel@tonic-gate  * determine whether an inode should be fixed.
465*0Sstevel@tonic-gate  */
466*0Sstevel@tonic-gate /* ARGSUSED1 */
467*0Sstevel@tonic-gate int32_t
468*0Sstevel@tonic-gate dofix(struct inodesc *idesc, char *msg)
469*0Sstevel@tonic-gate {
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	switch (idesc->id_fix) {
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 	case DONTKNOW:
474*0Sstevel@tonic-gate 		pwarn(msg);
475*0Sstevel@tonic-gate 		if (preen) {
476*0Sstevel@tonic-gate 			(void) printf(gettext(" (SALVAGED)\n"));
477*0Sstevel@tonic-gate 			idesc->id_fix = FIX;
478*0Sstevel@tonic-gate 			return (ALTERED);
479*0Sstevel@tonic-gate 		}
480*0Sstevel@tonic-gate 		if (reply(gettext("SALVAGE")) == 0) {
481*0Sstevel@tonic-gate 			idesc->id_fix = NOFIX;
482*0Sstevel@tonic-gate 			return (0);
483*0Sstevel@tonic-gate 		}
484*0Sstevel@tonic-gate 		idesc->id_fix = FIX;
485*0Sstevel@tonic-gate 		return (ALTERED);
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	case FIX:
488*0Sstevel@tonic-gate 		return (ALTERED);
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	case NOFIX:
491*0Sstevel@tonic-gate 		return (0);
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	default:
494*0Sstevel@tonic-gate 		errexit(gettext("UNKNOWN INODESC FIX MODE %d\n"),
495*0Sstevel@tonic-gate 			idesc->id_fix);
496*0Sstevel@tonic-gate 	}
497*0Sstevel@tonic-gate 	/* NOTREACHED */
498*0Sstevel@tonic-gate }
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate /*
501*0Sstevel@tonic-gate  * Check to see if unraw version of name is already mounted.
502*0Sstevel@tonic-gate  * Since we do not believe /etc/mnttab, we stat the mount point
503*0Sstevel@tonic-gate  * to see if it is really looks mounted.
504*0Sstevel@tonic-gate  */
505*0Sstevel@tonic-gate mounted(char *name)
506*0Sstevel@tonic-gate {
507*0Sstevel@tonic-gate 	int found = 0;
508*0Sstevel@tonic-gate 	struct mnttab mnt;
509*0Sstevel@tonic-gate 	FILE *mnttab;
510*0Sstevel@tonic-gate 	struct stat device_stat, mount_stat;
511*0Sstevel@tonic-gate 	char *blkname, *unrawname();
512*0Sstevel@tonic-gate 	int err;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	mnttab = fopen(MNTTAB, "r");
515*0Sstevel@tonic-gate 	if (mnttab == NULL) {
516*0Sstevel@tonic-gate 		(void) printf(gettext("can't open %s\n"), MNTTAB);
517*0Sstevel@tonic-gate 		return (0);
518*0Sstevel@tonic-gate 	}
519*0Sstevel@tonic-gate 	blkname = unrawname(name);
520*0Sstevel@tonic-gate 	while ((getmntent(mnttab, &mnt)) == NULL) {
521*0Sstevel@tonic-gate 		if (strcmp(mnt.mnt_fstype, MNTTYPE_UDFS) != 0) {
522*0Sstevel@tonic-gate 			continue;
523*0Sstevel@tonic-gate 		}
524*0Sstevel@tonic-gate 		if (strcmp(blkname, mnt.mnt_special) == 0) {
525*0Sstevel@tonic-gate 			err = stat(mnt.mnt_mountp, &mount_stat);
526*0Sstevel@tonic-gate 			err |= stat(mnt.mnt_special, &device_stat);
527*0Sstevel@tonic-gate 			if (err < 0)
528*0Sstevel@tonic-gate 				continue;
529*0Sstevel@tonic-gate 			if (device_stat.st_rdev == mount_stat.st_dev) {
530*0Sstevel@tonic-gate 				(void) strncpy(mnt.mnt_mountp, mountpoint,
531*0Sstevel@tonic-gate 					sizeof (mountpoint));
532*0Sstevel@tonic-gate 				if (hasmntopt(&mnt, MNTOPT_RO) != 0)
533*0Sstevel@tonic-gate 					found = 2;	/* mounted as RO */
534*0Sstevel@tonic-gate 				else
535*0Sstevel@tonic-gate 					found = 1; 	/* mounted as R/W */
536*0Sstevel@tonic-gate 			}
537*0Sstevel@tonic-gate 			break;
538*0Sstevel@tonic-gate 		}
539*0Sstevel@tonic-gate 	}
540*0Sstevel@tonic-gate 	(void) fclose(mnttab);
541*0Sstevel@tonic-gate 	return (found);
542*0Sstevel@tonic-gate }
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate /*
545*0Sstevel@tonic-gate  * Check to see if name corresponds to an entry in vfstab, and that the entry
546*0Sstevel@tonic-gate  * does not have option ro.
547*0Sstevel@tonic-gate  */
548*0Sstevel@tonic-gate writable(char *name)
549*0Sstevel@tonic-gate {
550*0Sstevel@tonic-gate 	int rw = 1;
551*0Sstevel@tonic-gate 	struct vfstab vfsbuf;
552*0Sstevel@tonic-gate 	FILE *vfstab;
553*0Sstevel@tonic-gate 	char *blkname, *unrawname();
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 	vfstab = fopen(VFSTAB, "r");
556*0Sstevel@tonic-gate 	if (vfstab == NULL) {
557*0Sstevel@tonic-gate 		(void) printf(gettext("can't open %s\n"), VFSTAB);
558*0Sstevel@tonic-gate 		return (1);
559*0Sstevel@tonic-gate 	}
560*0Sstevel@tonic-gate 	blkname = unrawname(name);
561*0Sstevel@tonic-gate 	if ((getvfsspec(vfstab, &vfsbuf, blkname) == 0) &&
562*0Sstevel@tonic-gate 	    (vfsbuf.vfs_fstype != NULL) &&
563*0Sstevel@tonic-gate 	    (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UDFS) == 0) &&
564*0Sstevel@tonic-gate 	    (hasvfsopt(&vfsbuf, MNTOPT_RO))) {
565*0Sstevel@tonic-gate 		rw = 0;
566*0Sstevel@tonic-gate 	}
567*0Sstevel@tonic-gate 	(void) fclose(vfstab);
568*0Sstevel@tonic-gate 	return (rw);
569*0Sstevel@tonic-gate }
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate /*
572*0Sstevel@tonic-gate  * print out clean info
573*0Sstevel@tonic-gate  */
574*0Sstevel@tonic-gate void
575*0Sstevel@tonic-gate printclean()
576*0Sstevel@tonic-gate {
577*0Sstevel@tonic-gate 	char	*s;
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 	switch (lvintp->lvid_int_type) {
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 	case LVI_CLOSE:
582*0Sstevel@tonic-gate 		s = gettext("clean");
583*0Sstevel@tonic-gate 		break;
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	case LVI_OPEN:
586*0Sstevel@tonic-gate 		s = gettext("active");
587*0Sstevel@tonic-gate 		break;
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	default:
590*0Sstevel@tonic-gate 		s = gettext("unknown");
591*0Sstevel@tonic-gate 	}
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 	if (preen)
594*0Sstevel@tonic-gate 		pwarn(gettext("is %s.\n"), s);
595*0Sstevel@tonic-gate 	else
596*0Sstevel@tonic-gate 		(void) printf("** %s is %s.\n", devname, s);
597*0Sstevel@tonic-gate }
598